refactor(frontend) fix template searching, update database images

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2024-08-25 18:20:46 -07:00
parent 6e503f957a
commit f40437e94e
65 changed files with 187 additions and 96 deletions

View File

@@ -15,18 +15,20 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib widget\n",
"import json\n",
"\n",
"database = {}\n",
"\n",
"with open(\"data/database.json\", \"r\") as f:\n",
" database = json.load(f)\n",
"with open(\"src/ts/virtualMachine/prefabDatabase.ts\", \"r\") as f:\n",
" contents = f.read().removeprefix(\"export default \").removesuffix(\" as const\")\n",
" database = json.loads(contents)\n",
"\n",
"db = database[\"db\"]"
"db = database[\"prefabs\"]"
]
},
{
@@ -38,7 +40,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@@ -58,7 +60,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
@@ -80,7 +82,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
@@ -105,9 +107,9 @@
" better_matches = []\n",
" for can in filtered_matches:\n",
" name, match, mapping = can\n",
" if mapping.startswith(\"Item\") and mapping in name:\n",
" if mapping.startswith(\"Item\") and mapping in name or mapping.lower() in name:\n",
" better_matches.append((name, match, mapping))\n",
" elif mapping.startswith(\"Structure\") and mapping in name:\n",
" elif mapping.startswith(\"Structure\") and mapping in name or mapping.lower() in name:\n",
" better_matches.append((name, match, mapping))\n",
" if len(better_matches) > 0:\n",
" filtered_matches = better_matches\n",
@@ -127,7 +129,7 @@
" direct = []\n",
" for can in filtered_matches:\n",
" name, match, mapping = can\n",
" if f\"{match}-\" in name:\n",
" if f\"{match}-\" in name or f\"{match.lower()}-\" in name:\n",
" direct.append((name, match, mapping))\n",
" if len(direct) > 0:\n",
" filtered_matches = direct\n",
@@ -154,7 +156,7 @@
" continue\n",
" elif name.startswith(\"Kit\") and not mapping.startswith(\"Kit\"):\n",
" continue\n",
" elif not name.startswith(match):\n",
" elif not (name.startswith(match) or name.startswith(match.lower())):\n",
" continue\n",
" not_worse.append((name, match, mapping))\n",
" if len(not_worse) > 0:\n",
@@ -171,14 +173,15 @@
"\n",
"for entry in db.values():\n",
" candidates = []\n",
" entry_name = entry[\"prefab\"][\"prefab_name\"]\n",
" for name in names:\n",
" if entry[\"name\"] in name:\n",
" candidates.append((name, entry[\"name\"], entry[\"name\"]))\n",
" if entry[\"name\"].removeprefix(\"Item\") in name:\n",
" candidates.append((name, entry[\"name\"].removeprefix(\"Item\"), entry[\"name\"]))\n",
" if entry[\"name\"].removeprefix(\"Structure\") in name:\n",
" candidates.append((name, entry[\"name\"].removeprefix(\"Structure\"), entry[\"name\"]))\n",
" image_candidates[entry[\"name\"]] = filter_candidates(candidates)"
" if entry_name in name or entry_name.lower() in name:\n",
" candidates.append((name, entry_name, entry_name))\n",
" if entry_name.removeprefix(\"Item\") in name or entry_name.removeprefix(\"Item\").lower() in name:\n",
" candidates.append((name, entry_name.removeprefix(\"Item\"), entry_name))\n",
" if entry_name.removeprefix(\"Structure\") in name or entry_name.removeprefix(\"Structure\").lower() in name:\n",
" candidates.append((name, entry_name.removeprefix(\"Structure\"), entry_name))\n",
" image_candidates[entry_name] = filter_candidates(candidates)"
]
},
{
@@ -190,7 +193,7 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
@@ -206,12 +209,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Prepare out List of file copies. at this point a few items will never have a match. and one or two will have two choices but those choices will be arbitrary."
"Prepare out List of file copies. at this point a few items will never have a match. and one or two will have two choices but those choices will be filtered again by passing them through some extra function."
]
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": 40,
"metadata": {},
"outputs": [
{
@@ -227,25 +230,87 @@
"ItemHorticultureBelt []\n",
"ItemKitLiquidRegulator []\n",
"ItemKitPortablesConnector []\n",
"ItemMushroom ['ItemMushroom-resources.assets-3022.png', 'ItemMushroom-resources.assets-9304.png']\n",
"ItemPlantEndothermic_Creative []\n",
"ItemPlantThermogenic_Creative []\n",
"ItemSuitModCryogenicUpgrade []\n",
"Landingpad_GasConnectorInwardPiece []\n",
"Landingpad_LiquidConnectorInwardPiece []\n",
"StructureBlocker []\n",
"StructureElevatorLevelIndustrial []\n",
"StructureLogicSorter []\n",
"StructurePlinth []\n"
]
}
],
"source": [
"%matplotlib widget\n",
"to_copy = []\n",
"\n",
"from IPython.display import Image, display\n",
"\n",
"gases = [(\"Oxygen\", \"White\"), (\"Nitrogen\", \"Black\"), (\"CarbonDioxide\", \"Yellow\"), (\"Fuel\", \"Orange\")]\n",
"\n",
"colors = [\"White\", \"Black\", \"Gray\", \"Khaki\", \"Brown\", \"Orange\", \"Yellow\", \"Red\", \"Green\", \"Blue\", \"Purple\"]\n",
"\n",
"def split_gas(name):\n",
" for gas, color in gases:\n",
" if name.endswith(gas):\n",
" return (name.removesuffix(gas), gas, color)\n",
" elif name.lower().endswith(gas):\n",
" return (name.lower().removesuffix(gas), gas, color)\n",
" elif name.lower().endswith(gas.lower()):\n",
" return (name.lower().removesuffix(gas.lower()), gas.lower(), color.lower())\n",
" return [name, None, None]\n",
"\n",
"def match_gas_color(name, candidates):\n",
" mat, gas, color = split_gas(name)\n",
" seek = f\"{mat}_{color}\"\n",
" if gas is not None:\n",
" for candidate in candidates:\n",
" if seek in candidate or seek.lower() in candidate:\n",
" return candidate\n",
" return None\n",
"\n",
"def prefer_direct(name, candidates):\n",
" for candidate in candidates:\n",
" if f\"{name}-\" in candidate or f\"{name.lower()}-\" in candidate:\n",
" return candidate\n",
" return None\n",
"\n",
"def prefer_uncolored(name, candidates):\n",
" for candidate in candidates:\n",
" for color in colors:\n",
" if f\"_{color}\" not in candidate and f\"_{color.lower()}\" not in candidate:\n",
" return candidate\n",
" return None\n",
"\n",
"def prefer_lower_match(name, candidates):\n",
" for candidate in candidates:\n",
" if f\"{name.lower()}-\" in candidate:\n",
" return candidate\n",
" return None\n",
"\n",
"filter_funcs = [prefer_lower_match, prefer_direct, match_gas_color, prefer_uncolored]\n",
"\n",
"for name, candidates in image_candidates.items():\n",
" if len(candidates) != 1:\n",
" found = False\n",
" for func in filter_funcs:\n",
" candidate = func(name, candidates)\n",
" if candidate is not None:\n",
" to_copy.append((name, candidate))\n",
" found = True\n",
" if found:\n",
" continue\n",
" print(name, candidates)\n",
" if len(candidates) > 1:\n",
" for candidate in candidates:\n",
" print(candidate)\n",
" display(Image(datapath / candidate))\n",
" \n",
" #take first as fallback\n",
" to_copy.append((name, candidates[0]))\n",
" # to_copy.append((name, candidates[0]))\n",
" raise StopExecution\n",
" else:\n",
" # print(name, candidates)\n",
" to_copy.append((name, candidates[0]))\n"
@@ -253,7 +318,7 @@
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 41,
"metadata": {},
"outputs": [
{
@@ -334,14 +399,28 @@
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3497a8d33d6a45879586d4c7441e3f60",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"IntProgress(value=0, max=1288)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"1266 of 1266 | 100.00% \n",
"1288 of 1288 | 100.00% \n",
"Done\n"
]
}
@@ -352,6 +431,12 @@
"destpath = Path(\"img/stationpedia\")\n",
"total_files = len(to_copy)\n",
"\n",
"from ipywidgets import IntProgress\n",
"from IPython.display import display\n",
"import time\n",
"\n",
"f = IntProgress(min=0, max=total_files)\n",
"display(f)\n",
"count = 0\n",
"print ( f\"{count} of {total_files} | { count / total_files * 100}\", end=\"\\r\")\n",
"for name, file in to_copy:\n",
@@ -359,6 +444,7 @@
" dest = destpath / f\"{name}.png\"\n",
" shutil.copy(source, dest)\n",
" count += 1\n",
" f.value = count\n",
" print ( f\"{count} of {total_files} | { (count / total_files) * 100 :.2f}% \", end=\"\\r\")\n",
"print()\n",
"print(\"Done\")\n",
@@ -382,7 +468,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.2"
"version": "3.12.5"
}
},
"nbformat": 4,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -55,7 +55,7 @@ export function crc32(str: string): number {
export function numberToString(n: number): string {
if (isZeroNegative(n)) return "-0";
return n.toString();
return n?.toString() ?? `${n}`;
}
export function displayNumber(n: number): string {
return numberToString(n).replace("Infinity", "∞");

View File

@@ -76,7 +76,7 @@ export class VMICControls extends VMObjectMixin(SignalWatcher(BaseElement)) {
}
this.selectUpdateTimeout = setTimeout(() => {
if (this.activeICSelect.value != null) {
this.activeICSelect.value.value = this.activeIC.value.toString();
this.activeICSelect.value.value = this.activeIC.value?.toString() ?? "";
this.activeICSelect.value.handleValueChange();
}
}, 100);

View File

@@ -54,7 +54,7 @@ export class VMAddDeviceButton extends VMObjectMixin(BaseElement) {
let last: Map<string, LogicableStructureTemplate> = null
return computed(() => {
const next = new Map(
Array.from(Object.values(this.templateDB.value ?? {})).flatMap((template) => {
Array.from(this.templateDB.value?.values() ?? []).flatMap((template) => {
if ("structure" in template && "logic" in template) {
return [[template.prefab.prefab_name, template]] as [
string,
@@ -244,7 +244,7 @@ export class VMAddDeviceButton extends VMObjectMixin(BaseElement) {
(result) =>
html`
<vm-device-template
prefab_name=${result.entry.prefab.prefab_name}
prefabName=${result.entry.prefab.prefab_name}
class="card"
@add-device-template=${this._handleDeviceAdd}
>

View File

@@ -81,7 +81,7 @@ export class VMDevicePins extends VMObjectMixin(BaseElement) {
}
);
});
return pinsHtml;
return html`${watch(pinsHtml)}`;
}
_handleChangePin(e: CustomEvent) {

View File

@@ -11,6 +11,7 @@ import {
ItemInfo,
ObjectInfo,
ObjectTemplate,
TemplateDatabase,
} from "ic10emu_wasm";
import { computed, ReadonlySignal, signal, Signal, watch } from "@lit-labs/preact-signals";
import { repeat } from "lit/directives/repeat.js";
@@ -47,7 +48,7 @@ export class VMSlotAddDialog extends VMObjectMixin(BaseElement) {
this._filter.value = val;
}
templateDB = computed(() => {
templateDB = computed((): TemplateDatabase => {
return this.vm.value?.state.templateDB.value ?? null;
});
@@ -55,7 +56,7 @@ export class VMSlotAddDialog extends VMObjectMixin(BaseElement) {
let last: { [k: string]: SlotableItemTemplate } = null;
return computed(() => {
const next = Object.fromEntries(
Array.from(Object.values(this.templateDB.value ?? {})).flatMap((template) => {
Array.from(this.templateDB.value?.values() ?? []).flatMap((template) => {
if ("item" in template) {
return [[template.prefab.prefab_name, template]] as [
string,
@@ -82,7 +83,7 @@ export class VMSlotAddDialog extends VMObjectMixin(BaseElement) {
if (isSome(obj)) {
const template = obj.template;
const slot = "slots" in template ? template.slots[this.slotIndex.value] : null;
const typ = slot.typ;
const typ = slot?.typ;
if (typeof typ === "string" && typ !== "None") {
filtered = Array.from(Object.values(this.items.value)).filter(
@@ -238,10 +239,6 @@ export class VMSlotAddDialog extends VMObjectMixin(BaseElement) {
const div = e.currentTarget as HTMLDivElement;
const key = parseInt(div.getAttribute("key"));
const entry = this.templateDB.value.get(key) as SlotableItemTemplate;
const obj = window.VM.vm.state.getObject(this.objectID);
const dbTemplate = obj.peek().template;
console.log("using entry", dbTemplate);
const template: FrozenObject = {
obj_info: {
prefab: entry.prefab.prefab_name,
@@ -301,8 +298,8 @@ export class VMSlotAddDialog extends VMObjectMixin(BaseElement) {
}
_handleDialogHide() {
this.objectID = undefined;
this.slotIndex = undefined;
this.objectIDSignal.value = null;
this.slotIndex.value = null;
}
private slotIndex: Signal<number> = signal(0);

View File

@@ -20,7 +20,7 @@ import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { connectionFromConnectionInfo } from "./dbutils";
import { crc32, displayNumber, parseNumber, structuralEqual } from "utils";
import { crc32, displayNumber, isSome, parseNumber, structuralEqual } from "utils";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { VMDeviceCard } from "./card";
@@ -76,16 +76,16 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
`,
];
fields: Signal<Record<LogicType, number>>;
slots: Signal<SlotTemplate[]>;
pins: Signal<(ObjectID | undefined)[]>;
template: Signal<FrozenObject>;
objectId: Signal<number | undefined>;
objectName: Signal<string | undefined>;
connections: Signal<Connection[]>;
fields: Signal<Record<LogicType, number>> = signal(null);
slots: Signal<SlotTemplate[]> = signal([]);
pins: Signal<(ObjectID | null)[]> = signal(null);
template: Signal<FrozenObject> = signal(null);
objectId: Signal<number | null> = signal(null);
objectName: Signal<string | null> = signal(null);
connections: Signal<Connection[]> = signal([]);
private prefabNameSignal = signal(null);
private prefabHashSignal = computed(() => crc32(this.prefabNameSignal.value));
private prefabHashSignal = computed(() => crc32(this.prefabNameSignal.value ?? ""));
get prefabName(): string {
return this.prefabNameSignal.peek();
@@ -114,6 +114,10 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
constructor() {
super();
this.dbTemplate.subscribe(() => this.setupState())
this.prefabNameSignal.subscribe(() => this.setupState());
this.networkOptions.subscribe((_) => {
this.forceSelectUpdate(this.networksSelectRef);
})
}
setupState() {
@@ -122,8 +126,8 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
this.fields.value = Object.fromEntries(
(
Array.from(
"logic" in dbTemplate
? Object.entries(dbTemplate.logic.logic_types)
isSome(dbTemplate) && "logic" in dbTemplate
? dbTemplate.logic.logic_types.entries()
: [],
) as [LogicType, MemoryAccess][]
).map(([lt, access]) => {
@@ -134,7 +138,7 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
) as Record<LogicType, number>;
this.slots.value = (
("slots" in dbTemplate ? dbTemplate.slots ?? [] : []) as SlotInfo[]
(isSome(dbTemplate) && "slots" in dbTemplate ? dbTemplate.slots ?? [] : []) as SlotInfo[]
).map(
(slot, _index) =>
({
@@ -144,7 +148,7 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
);
const connections = (
"device" in dbTemplate
isSome(dbTemplate) && "device" in dbTemplate
? dbTemplate.device.connection_list
: ([] as ConnectionInfo[])
).map(
@@ -163,27 +167,30 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
this.connections.value = connections.map((conn) => conn[1]);
const numPins =
"device" in dbTemplate ? dbTemplate.device.device_pins_length : 0;
isSome(dbTemplate) && "device" in dbTemplate ? dbTemplate.device.device_pins_length : 0;
this.pins.value = new Array(numPins).fill(undefined);
}
renderFields(): HTMLTemplateResult {
const fields = Object.entries(this.fields);
return html`
${fields.map(([name, field], _index, _fields) => {
fieldsHtml = computed(() => {
const fields = Object.entries(this.fields.value);
fields.map(([name, field], _index, _fields) => {
return html`
<sl-input
key="${name}"
value="${displayNumber(field.value)}"
value="${displayNumber(field)}"
size="small"
@sl-change=${this._handleChangeField}
?disabled=${name === "PrefabHash"}
>
<span slot="prefix">${name}</span>
<span slot="suffix">${field.field_type}</span>
</sl-input>
`;
})}
});
});
renderFields(): HTMLTemplateResult {
return html`
${watch(this.fieldsHtml)}
`;
}
@@ -191,7 +198,7 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
const input = e.target as SlInput;
const field = input.getAttribute("key")! as LogicType;
const val = parseNumber(input.value);
this.fields.value = { ...this.fields.value, [field]: val};
this.fields.value = { ...this.fields.value, [field]: val };
if (field === "ReferenceId" && val !== 0) {
this.objectIDSignal.value = val;
}
@@ -224,38 +231,34 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
return vm?.state.networkIds.value.map(net => html`<sl-option value=${net}>Network ${net}</sl-option>`);
});
renderNetworks() {
const vm = window.VM.vm;
this.networkOptions.subscribe((_) => {
this.forceSelectUpdate(this.networksSelectRef);
})
const connections = computed(() => {
this.connections.value.map((connection, index, _conns) => {
const conn =
typeof connection === "object" && "CableNetwork" in connection
? connection.CableNetwork
: null;
return html`
<sl-select
hoist
placement="top"
clearable
key=${index}
value=${conn?.net}
?disabled=${conn === null}
@sl-change=${this._handleChangeConnection}
${ref(this.networksSelectRef)}
>
<span slot="prefix">Connection:${index} </span>
${watch(this.networkOptions)}
<span slot="prefix"> ${conn?.typ} </span>
</sl-select>
`;
});
connectionsHtml = computed(() => {
this.connections.value?.map((connection, index, _conns) => {
const conn =
typeof connection === "object" && "CableNetwork" in connection
? connection.CableNetwork
: null;
return html`
<sl-select
hoist
placement="top"
clearable
key=${index}
value=${conn?.net}
?disabled=${conn === null}
@sl-change=${this._handleChangeConnection}
${ref(this.networksSelectRef)}
>
<span slot="prefix">Connection:${index} </span>
${watch(this.networkOptions)}
<span slot="prefix"> ${conn?.typ} </span>
</sl-select>
`;
});
});
renderNetworks() {
return html`
<div class="networks">
${watch(connections)}
${watch(this.connectionsHtml)}
</div>
`;
}
@@ -271,7 +274,7 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
private _pinsSelectRefMap: Map<number, Ref<SlSelect>> = new Map();
getPinRef(index: number) : Ref<SlSelect> {
getPinRef(index: number): Ref<SlSelect> {
if (!this._pinsSelectRefMap.has(index)) {
this._pinsSelectRefMap.set(index, createRef());
}
@@ -359,8 +362,8 @@ export class VmObjectTemplate extends VMObjectMixin(BaseElement) {
render() {
const device = this.dbTemplate;
const prefabName = computed(() => device.value.prefab.prefab_name);
const name = computed(() => device.value.prefab.name);
const prefabName = computed(() => device.value?.prefab.prefab_name ?? "");
const name = computed(() => device.value?.prefab.name ?? "");
return html`
<sl-card class="template-card">
<div class="header h-20 w-96" slot="header">

View File

@@ -526,7 +526,12 @@ export class VMState {
if (!this.signalCacheHas(key)) {
const s = computed((): number => {
const obj = this.getObject(id).value;
return [...obj?.obj_info.device_pins?.keys() ?? []].length;
const template = obj?.template;
let numPins = [...obj?.obj_info.device_pins?.keys() ?? []].length;
if (isSome(template) && "device" in template) {
numPins = template.device.device_pins_length ?? 0;
}
return numPins;
});
this.signalCacheSet(key, s);
return s;