DataMind Oda's interface is built from slots: named places that render the components a plugin contributes. Everything a plugin adds to the interface goes through the slots API, and this page is its contract: the registration call, the shape of a slot, the client services your code can use, and the rules your styles, routes and copy must follow.
How a plugin's code reaches the interface is on How client plugins load; the running side of a package is on The browser half of a dynamic package.
ctx. slots. register(options, Component), and the component it registers is what the slot renders.slots in the plugin's inject, or the seat is withheld.ctx. slots. inject(key, () => . . . ): registering into a slot whose owner is not mounted throws, and the wrapper runs your registration again when the owner mounts.React. createElement and inserts styles with styles. insert(css) instead of importing modules.A minimal entry looks like this:
return {
inject: ['slots'],
apply(ctx) {
ctx.slots.inject('<slot key>', () =>
ctx.slots.register({ name: 'my-entry' }, () =>
React.createElement('div', null, 'Hello'),
),
);
},
};The catalog entry for the slot you choose states exactly which options the call must pass.
single, list, keyed and chain; a single or keyed slot renders one entry, so those are the kinds that can shadow shipped UI, and a list slot renders several entries, sorted by their order.root, session or session-maybe, and a component receives the framework hooks of its slot's scope: useSessions(state => state. current) is a session hook that reads the current chat.shadows-shipped-ui in the catalog, and a registration there replaces the shipped interface; the root slot is one, since it carries the application frame.id, order, label, key and select. An order is the entry's position among the slot's entries, ascending, default 0. A keyed slot also defines the key's domain: it may be open, any string the owner dispatches, or fixed by the owner's key table, which says which keys are already taken.inject, and they resolve before the plugin starts.| Service | Methods | What it covers |
|---|---|---|
slots | register, registerFactory, inject | The registration surface on this page. |
layout | selectPanel, beginNavigation, toggleSidebar, openRightbar, closeRightbar | What the app shows around your UI: the panel in view, navigation, the sidebar and the right bar. |
sessions | retain, using, retainInfo, refreshProjections, search, fork, scope, binding | The chats: searching, forking and following their state. |
uiWorkspace | openSession, openWorkspace, forkSession, connectWorkspace, startSession, archiveSession, unarchiveSession, pickDirectory, listDirectory, createDirectory | Opening and moving around: workspaces and chats, starting, forking, archiving and restoring them, and picking, listing or creating folders. |
workspaces | create, rename, delete, insertSessionBefore, archiveSession, unarchiveSession | The workspace list: creating, renaming, deleting, ordering and archiving. |
theme | getTheme, setTheme, setFontSize, register, overrideTokens | Reading and setting the theme and text size, and registering or overriding theme tokens. |
locale | getLocale, getSnapshot, subscribe, setLocale, addLanguage, register, bind | The running language: reading it, following changes, and registering a language and its dictionaries. |
The notes are orientation only; query a service through the inspection tools for its exact contract. Read the directory in your installation instead of assuming a name is there, since availability can differ between installations. A browser half can also declare timer for timer helpers; The browser half of a dynamic package covers that service.
var(--dsw-alias-bg-layer-1) and var(--dsw-alias-label-primary).theme and override tokens with overrideTokens; the override belongs to your plugin and is removed when it unloads.Code that runs in the interface addresses the app's own routes under three prefixes: api, plugins and open-in-app. Three rules keep a route resolvable:
api/ x; a root-absolute path is rejected.alt, aria-label, placeholder and title.The set includes slots, layout, sessions, uiWorkspace, workspaces, theme and locale, and a browser half can also declare timer. Declare what you use in inject, and query the inspection tools for the exact contract, since availability can differ between installations.
A slot's kind is one of single, list, keyed and chain: a single or keyed slot renders one entry, and a list slot renders several, sorted by their order. A slot's scope (root, session or session-maybe) names the context its component runs in: components receive the framework hooks of their slot's scope, and useSessions(state => state. reads the current chat.
Pass the order the slot documents: it is the entry's position among the slot's entries, ascending, with a default of 0.
shadows-shipped-ui mean in the catalog?It is the catalog's mark on a single or keyed slot that already ships an occupant, such as the root slot, which carries the application frame. In such a slot your entry is the one that renders, so a registration there replaces the shipped interface; a priority is assigned for you, lower than every shipped entry, and you never pass one yourself.
No. The locale dictionaries are the only files allowed to own translated text, and copy hard-coded in component code is rejected, including text in copy-bearing attributes such as alt, aria-label, placeholder and title. Put the string in a dictionary and reference it from the component.
English. Every string resolves through the locale service, and a language pack can add another language; the calls and rules are on Language packs.
Write it document-relative under the api, plugins or open-in-app prefix, as in api/; resolve it against the document's base address, and strip the leading slash before the browser uses a shared route key. A root-absolute path is rejected.
No. Base the look on the theme's CSS variables, var(--dsw-alias-bg-layer-1) and var(--dsw-alias-label-primary), and override tokens through the theme service where your UI needs its own colours; an override is yours and goes away when your plugin unloads.
The client side of the inspection tools serves it: list the providers first, then query the client platform, and the answer carries the slots with their kinds, scopes and the options each registration must pass. Registrations that failed can be read back there too; see Inspect and manage extensions.