Skip to content
Back to skills

Association Entity Select

ASecurity

AssociationEntitySelect, the name dropdown for the note, session, chat, or document a panel is bound to. Use when a surface must show that name and let the user rename, switch, unlink, or add new ('add a note switcher', 'show the session name'). NOT for count cards or row lists (use canonical-associations).

  • 3 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 3, 2026
devopsgoreactnodeapi

Works with

  • terminal
  • cli
  • api

Security analysis

A100/100

Scanned October 3, 2026

npx -y skills add armanisadeghi/ai-matrx --skill association-entity-select --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Association Entity Select?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Association Entity Select
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/armanisadeghi-association-entity-select/badge)](https://www.skillsdirectory.com/skills/armanisadeghi-association-entity-select)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: association-entity-select
description: "AssociationEntitySelect, the name dropdown for the note, session, chat, or document a panel is bound to. Use when a surface must show that name and let the user rename, switch, unlink, or add new ('add a note switcher', 'show the session name'). NOT for count cards or row lists (use canonical-associations)."
---

# AssociationEntitySelect — the canonical name dropdown

> **W5 SWAP NOTICE (2026-08-29):** the association/category UI + hooks + service
> implementations now ship in **`@ai-matrx/associations`** (`/react` for faces +
> hooks, `/core` for the headless services/store). Paths in this document that
> point at `features/scopes/components/associations/**`,
> `features/scopes/components/Category*`, or `features/scopes/redux/**`
> association/category fragments refer to DELETED files — import from
> `@ai-matrx/associations/react` (hooks also re-exported under
> `features/scopes/hooks/`), and see `features/scopes/host/` for the host
> binding. The rules and contracts described remain in force.


**One control, five jobs, per (token, container):** display the active entity's real name (registry icon) · inline rename (click the name) · switch via an **always-visible** dropdown (searchable past 5 items) · per-row unlink (non-active rows, edge only — never deletes the entity) · trailing **"+ New \<Entity\>"** that creates + associates + activates (typed search text doubles as the new name).

Component: `features/scopes/components/associations/AssociationEntitySelect.tsx`. Redux-free; everything flows through an **adapter**. Docs: `features/scopes/FEATURE.md` §"Association cards + list".

## The CREATE-then-ASSOCIATE contract (applies to EVERY association surface)

Two component classes, one law each:

1. **Associate-existing** (pickers, "Add" panels): the ONLY job is the edge — it must be written and verified (`AssociationWriteResult.ok`), and failure must toast. An "attach" that silently no-ops is the bug class.
2. **Create-then-associate** (upload file → attach, "+ New Note", new doc → attach): the item is created FIRST (durable row — it exists in the user's library regardless of what happens next), the edge is written SECOND (idempotent, retry-once is safe). **Every terminal outcome is loud, and a created-but-unlinked item is reported WITH its location** ("Uploaded to your Files (War Room folder) but couldn't attach — use Add file to retry"). The user gesture must never end in silence: cancellation, zero-result, create-failure, and attach-failure each get their own message. A created item that vanishes without a trace is the exact bug this contract kills.

References: `ThreadResourcesTab.handleFilesSelected` (upload → attach, all outcomes loud) and `useAssociationEntitySelectAdapter.createAndAttach` (create → attach with retry + created-but-unlinked toast).

## Rules

- **Never rebuild any face of this** — no bespoke note/session switchers, no standalone rename spans next to a separate dropdown, no "+ New X" menu items wired by hand. If a toolbar shows an entity's name, this component owns that name.
- **The dropdown never hides.** `items.length === 1` (or 0) still renders the chevron — "add another" must always be reachable. That gap is the bug this component exists to kill.
- Unlink ≠ delete: `detach` removes the association edge only. The active row never shows the X (switch first).
- Registry-driven: icon/labels come from `getEntityInfo(token)`. The token needs a `titleColumn` in `ENTITY_OVERLAY` (`features/scopes/registry/entityRegistry.ts`) for generic create/rename.
- **Not this control:** count cards (`AssociationCard`), row lists (`AssociationList`), and cross-type attach (`UniversalAssociationPicker`) — those faces are the `canonical-associations` skill.

## Plain container → default adapter

```tsx
import { AssociationEntitySelect } from "@/features/scopes/components/associations/AssociationEntitySelect";
import { useAssociationEntitySelectAdapter } from "@/features/scopes/hooks/useAssociationEntitySelect";

const adapter = useAssociationEntitySelectAdapter({
  token: "note",
  container: { type: "project", id: projectId, orgId },
  activeId,            // optional (controlled); omit → first attached row
  onActiveChange,      // optional
  createColumns: {},   // NOT NULL columns the registry conventions can't know
});
<AssociationEntitySelect token="note" adapter={adapter} />
```

Reads via `useContainerLinks` + `useEntityTitles`; creates via `createEntityRow` + `attach`; renames via `renameEntityRow`. Both row writes live in `features/scopes/service/entityRows.ts` (registry titleColumn + owner/org conventions, loud errors, primes `primeEntityTitle` so no surface renders stale).

## Bespoke lifecycle → implement `AssociationEntitySelectAdapter`

When the surface has its own active semantics or create pipeline, implement the interface (exported from the component file): `{ loading, items, activeId, setActive, createAndAttach, rename, detach? }`.

**Reference implementation:** `features/war-room/hooks/useThreadEntitySelect.ts` — `useThreadNoteSelectAdapter` (is_active edge metadata, notes autosave rename via `notesApi.update` + `upsertNoteFromServer`) and `useThreadAudioSessionSelectAdapter` (`studio_sessions` titles + `updateSessionThunk` rename). Consumers: `ThreadNotesTab` / `ThreadAudioTab` / `ThreadAgentTab`.

Adapter contract details:
- `createAndAttach(title)` must create the row, write the association, AND make it active; return the new id or null. **Optional** — omit it when creation isn't name-driven and pass the component's **`createSlot`** instead: a custom footer (ReactNode or `(close) => ReactNode`) replacing the name-input creator. Reference: the war-room Chat tab passes the canonical `AgentListDropdown` — "+ New Chat" = pick an AGENT, which mints a conversation (`startThreadConversation`); the label shows the agent's name until the server auto-labels the conversation after its first turn (`useThreadConversationSelectAdapter`'s label chain).
- `rename(id, title)` returns false on failure (the component toasts + keeps the editor open). Call `primeEntityTitle(token, id, title)` on success.
- Items carry real titles — positional fallbacks (`Note 2`, `Recording 3`) only for unhydrated rows.

## Props worth knowing

`renameActivation` ("click" | "doubleClick", default click) · `align` · `emptyLabel` · `showIcon` / `iconClassName` · `className` / `labelClassName`. Toolbar-dense by default (h-6, text-xs).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…