Skip to content

Comments

Allow opening linked filedef in the stack#4013

Open
jurgenwerk wants to merge 11 commits intomainfrom
cs-10185-clicking-on-filedef-in-interact-mode-should-successfully
Open

Allow opening linked filedef in the stack#4013
jurgenwerk wants to merge 11 commits intomainfrom
cs-10185-clicking-on-filedef-in-interact-mode-should-successfully

Conversation

@jurgenwerk
Copy link
Contributor

@jurgenwerk jurgenwerk commented Feb 18, 2026

This PR adds the ability to click on a FileDef, which opens as a card in the stack.

Here is an example with a @field featuredImage = linksTo(ImageDef);:

Screen.Recording.2026-02-20.at.10.32.48.mov

@github-actions
Copy link

Preview deployments

@github-actions
Copy link

github-actions bot commented Feb 18, 2026

Host Test Results

    1 files  ±0      1 suites  ±0   1h 43m 32s ⏱️ + 3m 25s
1 857 tests +1  1 843 ✅ +1  14 💤 ±0  0 ❌ ±0 
1 872 runs  +1  1 858 ✅ +1  14 💤 ±0  0 ❌ ±0 

Results for commit cb32ae9. ± Comparison against base commit 8d45ff7.

♻️ This comment has been updated with latest results.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds the ability to click on a linked FileDef in operator mode, which opens it as a card in the stack. The implementation introduces a type system to distinguish between regular cards and file-meta instances throughout the stack handling logic.

Changes:

  • Introduced StackItemType to track whether stack items are 'card' or 'file-meta' instances
  • Added optional type parameter to getCard function and CardResource to support loading file-meta instances
  • Implemented read-only behavior for file-meta cards (no edit mode, always isolated format)

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/runtime-common/index.ts Added optional type parameter to getCard function signature
packages/host/app/lib/stack-item.ts Added StackItemType field and type inference logic to stack items
packages/host/app/lib/read-type.ts New utility function to infer store read type from URL patterns
packages/host/app/resources/card-resource.ts Extended CardResource to support both card and file-meta types with fallback logic
packages/host/app/services/store.ts Updated reference management to handle file-meta type wiring
packages/host/app/services/operator-mode-state-service.ts Added type tracking in serialization/deserialization and prevented editing of file-meta items
packages/host/app/components/operator-mode/stack-item.gts Added file card detection and forced isolated format for file-meta instances
packages/host/app/components/operator-mode/overlays.gts Passed CardDef instances (not just URLs) to viewCard handler for type detection
packages/host/app/components/operator-mode/operator-mode-overlays.gts Disabled edit button for file-meta targets
packages/host/app/components/operator-mode/preview-panel/index.gts Added type parameter when opening cards in interact mode
packages/host/app/components/operator-mode/interact-submode.gts Added type inference logic for stack items based on instance or store state
packages/host/app/components/host-mode/*.gts Added type inference using URL patterns for host mode components
packages/base/links-to-editor.gts Formatting change only (split hash onto multiple lines)
packages/host/tests/integration/components/operator-mode-ui-test.gts Added test verifying linked files open in stack with correct type
packages/host/tests/acceptance/file-chooser-test.gts Updated test expectation to include type field in serialized state

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +120 to +122
return this.readType === 'file-meta'
? Boolean(this.store.peek(this.#id, { type: 'file-meta' }))
: Boolean(this.store.peek(this.#id));
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isLoaded getter doesn't use the fallback logic that the card getter uses (lines 91-93). This means if the type hint is incorrect, isLoaded could return false even when the card/file-meta instance is actually loaded in the store under the other type. Consider updating this getter to also check the fallback type, similar to how the card getter works.

Suggested change
return this.readType === 'file-meta'
? Boolean(this.store.peek(this.#id, { type: 'file-meta' }))
: Boolean(this.store.peek(this.#id));
let maybeCard =
this.peekForType(this.readType) ??
this.peekForType(this.fallbackReadType);
return isCardInstance(maybeCard) || isFileDefInstance(maybeCard);

Copilot uses AI. Check for mistakes.
Comment on lines +261 to +276
private getStackItemType(
cardOrURL: CardDef | URL | string,
cardId: string,
): StackItemType {
if (
cardOrURL &&
typeof cardOrURL === 'object' &&
!(cardOrURL instanceof URL)
) {
return isFileDefInstance(cardOrURL as CardDef) ? 'file-meta' : 'card';
}
let fileMetaInstanceOrError =
this.store.peek(cardId, { type: 'file-meta' }) ??
this.store.peekError(cardId, { type: 'file-meta' });
return fileMetaInstanceOrError ? 'file-meta' : 'card';
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When cardOrURL is a URL string that points to a file (has extension, not .json), but the file-meta instance is not yet loaded in the store, this method will return 'card' instead of 'file-meta'. This could cause the wrong type to be used when opening a file via direct navigation. Consider using inferStoreReadType as a fallback when no instance is found in the store to correctly detect file URLs based on their extension pattern.

Copilot uses AI. Check for mistakes.
@jurgenwerk jurgenwerk requested review from a team and Copilot February 20, 2026 10:24
@jurgenwerk jurgenwerk marked this pull request as ready for review February 20, 2026 10:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb32ae9e82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +103 to +104
if (this.readType === 'file-meta' && this.peekForType('file-meta')) {
return undefined;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not suppress file-meta errors in card resource

When readType is 'file-meta', this early return hides real load failures because store.peek(id, { type: 'file-meta' }) can return a CardErrorJSONAPI, not just a successful FileDef. In that case cardError becomes undefined, so consumers that gate on !card && !cardError will show a loading state instead of surfacing the fetch error (e.g., missing/forbidden linked files opened in the stack).

Useful? React with 👍 / 👎.

Copy link
Contributor

@habdelra habdelra Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this comment is trying to convey the subtleties of peek returning local state when the server state is in error (as i was mentioning in another comment). consider peekLive() if you need to know the current server state of the instance.

// intentionally not awaiting this. we keep track of the promise in
// this.newReferencePromises
this.wireUpNewReference(id);
this.wireUpNewReference(id, readType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we add a test for file def reference counting? there are a bunch of reference count balancing tests in the store-test.gts, could we update this to include file def's in the mix too?

Comment on lines +71 to +72
? (this.store.peek(this.#id, { type: 'file-meta' }) as unknown)
: (this.store.peek(this.#id) as unknown);
Copy link
Contributor

@habdelra habdelra Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

be aware there is a very subtle nuance around peeking. if the server state of the instance is in error and the local state is not, then the peek will give u the local state. unsure if this effects what you are trying to do. there is a peekLive() that will give you the server state regardless of whether or not it is in error.

Comment on lines +4 to +15
export function isFileMetaId(id: string | null | undefined): boolean {
if (!id) {
return false;
}
return hasExtension(id) && !id.endsWith('.json');
}

export function inferStoreReadType(
id: string | null | undefined,
): StoreReadType {
return isFileMetaId(id) ? 'file-meta' : 'card';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an AI anti-pattern that I have had to fight . We should be using more explicit type specification, not inferring stuff from URLs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note from our call:

  • consider adding a subprotocol or url annotation/prefix in urls in operator mode state that differentiate between card or file
  • default should be card

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants