From 4b4bf6aaea6dbc051a1d654dcbdc3a79502e5b56 Mon Sep 17 00:00:00 2001 From: Ben Follington <5009316+bfollington@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:40:10 +1000 Subject: [PATCH] Fix ct-render edgecase When encountering a link to a cell we could end up rendering nothing. --- .../v2/components/ct-render/ct-render.test.ts | 51 +++++++++++++++++++ .../src/v2/components/ct-render/ct-render.ts | 23 ++++++--- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/v2/components/ct-render/ct-render.test.ts b/packages/ui/src/v2/components/ct-render/ct-render.test.ts index d656cf48f..90308abc0 100644 --- a/packages/ui/src/v2/components/ct-render/ct-render.test.ts +++ b/packages/ui/src/v2/components/ct-render/ct-render.test.ts @@ -2,6 +2,35 @@ import { describe, it } from "@std/testing/bdd"; import { expect } from "@std/expect"; import { CTRender } from "./ct-render.ts"; +class FakeCell { + runtime = { + recipeManager: { loadRecipe: async () => {} }, + runSynced: async () => {}, + }; + space = "fake-space"; + #path: string[]; + constructor(path: string[] = []) { + this.#path = path; + } + async sync() {} + equals(other: unknown) { + return other === this; + } + getAsNormalizedFullLink() { + return { + id: "of:fake", + space: this.space, + type: "application/json", + path: this.#path, + }; + } + getSourceCell() { + return { + get: () => ({ $TYPE: "fake-recipe" }), + }; + } +} + describe("CTRender", () => { it("should be defined", () => { expect(CTRender).toBeDefined(); @@ -20,4 +49,26 @@ describe("CTRender", () => { const element = new CTRender(); expect(element.cell).toBeUndefined(); }); + + it("loads recipe even when cell path is non-empty", async () => { + const element = new CTRender(); + (element as any)._renderContainer = {}; + const cell = new FakeCell(["charms", "0"]) as any; + + const loadCalls: string[] = []; + (element as any)._loadAndRenderRecipe = async (recipeId: string) => { + loadCalls.push(recipeId); + }; + + const renderCalls: unknown[] = []; + (element as any)._renderUiFromCell = async (c: unknown) => { + renderCalls.push(c); + }; + + (element as any).cell = cell; + await (element as any)._renderCell(); + + expect(loadCalls).toEqual(["fake-recipe"]); + expect(renderCalls.length).toBe(0); + }); }); diff --git a/packages/ui/src/v2/components/ct-render/ct-render.ts b/packages/ui/src/v2/components/ct-render/ct-render.ts index 2a6ae8daa..8150b624b 100644 --- a/packages/ui/src/v2/components/ct-render/ct-render.ts +++ b/packages/ui/src/v2/components/ct-render/ct-render.ts @@ -201,15 +201,24 @@ export class CTRender extends BaseElement { // Clean up any previous render this._cleanupPreviousRender(); - const isSubPath = this._isSubPath(this.cell); + let recipeId: string | undefined; + try { + recipeId = getRecipeIdFromCharm(this.cell); + } catch (error) { + this._log( + "cell did not resolve to a charm via getRecipeIdFromCharm", + error, + ); + } - if (isSubPath) { - this._log("cell is a subpath, rendering directly"); - await this._renderUiFromCell(this.cell); + if (recipeId) { + await this._loadAndRenderRecipe(recipeId); } else { - const recipeId = getRecipeIdFromCharm(this.cell); - if (recipeId) { - await this._loadAndRenderRecipe(recipeId); + const isSubPath = this._isSubPath(this.cell); + + if (isSubPath) { + this._log("cell is a subpath, rendering directly"); + await this._renderUiFromCell(this.cell); } else { this._log("no recipe id found, rendering cell directly"); await this._renderUiFromCell(this.cell);