# Collection plugins

Every collection is defined by a JSON configuration plus optional JavaScript. **Collection Settings... → Edit Code** opens both. The settings dialog edits the same configuration with forms, so you can mix: define fields and views in the dialog, add behavior in code.

## Configuration

A field has a stable `id`, a `label`, a `type` and a few options:

```json
{
  "id": "hours",
  "label": "Hours",
  "type": "number",
  "icon": "ti-clock",
  "many": false,
  "read_only": false,
  "active": true
}
```

Views have an `id`, a `label`, a `type`, the `field_ids` they show, and their sort, grouping and query. Keep ids stable when you rename things: values and views refer to fields by id. A `managed` section can mark fields, views or sidebar settings as controlled by the plugin, which disables them in the settings dialog.

## Formulas and property behavior

`this.properties.formula(name, fn)` computes a property; see [Formulas](../collections/formulas.md). `render()` draws a property your own way, `customSort()` sorts it your own way, and the choice hooks fill a Choice property's options from code.

## Custom views

Add a view with `"type": "custom"` to the configuration, then register its behavior:

```js
class Plugin extends CollectionPlugin {
  onLoad() {
    this.views.register("Timeline", (ctx) => {
      let nodes = new Map();
      return {
        onLoad() { /* build the view in ctx.element */ },
        onRefresh({records, invalidatedGuids}) { /* update changed records */ },
        onDestroy() { nodes.clear(); },
      };
    });
  }
}
```

`ctx` gives you the view's element, the visible properties, the records and navigation helpers. Keep the view's state inside the registration function: two panels can show the same view at once. `onRefresh` tells you which records changed; `null` means all of them, an empty set none. Update what changed instead of rebuilding everything.

Built-in views have hooks too, such as `afterRenderBoardCard()` for adding buttons to board cards.

## Commands and interface

| Extension | API |
| --- | --- |
| Command palette command | `this.ui.addCommandPaletteCommand()` |
| Status bar item | `this.ui.addStatusBarItem()` |
| Notification | `this.ui.addToaster()` |
| Custom panel | `this.ui.registerCustomPanelType()` |
| Sidebar widget | `this.ui.addSidebarWidget()` |
| Button on this collection | `this.addCollectionNavigationButton()` |

Use the UI API's buttons, icons and panels so your plugin looks like Thymer in every theme. Release timers and listeners in `onUnload()`; with hot reload, a plugin is unloaded and loaded many times.
