# Widget Tools Documentation

## Overview

Widget tools manage published widgets in Modyo Channels. After widgets are published through releases, they become available as "custom widgets" that can be added to pages.

**⚠️ Important**: For detailed instructions on editing widgets that are already published and used on pages, see [Editing Published Widgets](../../docs/EDITING_PUBLISHED_WIDGETS.md).

## Key Concepts

**Widget Definitions vs Custom Widgets:**
- **Widget Definitions**: Draft/editable versions managed through `widget-definition-*` tools (accessed via `/widget_definitions` endpoint)
- **Custom Widgets**: Published versions accessible through `widget-get-custom-widgets` (accessed via `/custom_widgets` endpoint - **deprecated name**, they ARE editable through widget definitions)
- Only custom widgets (published) can be added to pages
- Each has a unique `definition_uuid` (OID/SHA hash) for identification
- **Widget IDs change after publishing**, but UUIDs remain stable

**Widget Lifecycle:**
1. Create widget definition (`widget-definitions-create`)
2. Edit HTML/CSS/JS (`widget-definition-update`)
3. Publish via release (`release-create`)
4. Widget appears in custom widgets list
5. Add to pages using `definition_uuid`

## Tools

### channels-widgets-code-edit

Surgically edits **one** code section (`html` / `css` / `js`) of a widget
definition without re-sending the whole section. Read-modify-write happens
client-side, then only that section is written back (the other sections are
preserved by the partial `PUT`). Prefer this over `channels-widgets-manage`
for small code changes — fewer tokens and no risk of altering code you didn't
intend to touch.

**Operations:**
- `replace` — swap `search` → `replaceWith` (literal match). `all: true`
  replaces every occurrence; default replaces the first.
- `insert` — place `content` `before`/`after` the first `search` anchor.
- `append` — add `content` at the end of the section.

**Parameters:** `siteId`, `identifier` (UUID / name / widgetId), `section`
(`html`|`css`|`js`), `operation`, `search`, `replaceWith`, `content`,
`position` (`before`|`after`, default `after`), `all` (default `false`),
`preview` (default `false`).

**Safety / behavior:**
- If the `search`/anchor is not found, or the edit is a no-op, the tool
  returns `changed: false` with a reason and writes nothing.
- `preview: true` returns the computed new section (and byte counts) WITHOUT
  writing to Modyo.
- It edits a single widget definition — no page-level `PUT` and no dependency
  on an atomic page endpoint (that case is tracked separately in #53).

**Example — swap a CSS class across the whole section:**
```
channels-widgets-code-edit
siteId: 4777
identifier: "hero"
section: "html"
operation: "replace"
search: "class=\"btn-primary\""
replaceWith: "class=\"btn-outline-primary\""
all: true
```

### widget-get-custom-widgets

Lists all published custom widgets for a site, returning their definition UUIDs needed for adding widgets to pages.

**Use Cases:**
- Get definition UUIDs for adding widgets to pages
- Verify which widgets are published and available
- Search for specific widgets by name or tags
- Audit published widget inventory
- Find widgets for page layouts

**Parameters:**
- `platformSlug` (required): Platform identifier from platforms.json
- `siteId` (required): Numeric ID of the site
- `query` (optional): Search keywords to filter by label/name
- `sort_by` (optional): Field to sort by
  - `"type"` - Widget type
  - `"widget_class_name"` - Class name
  - `"label"` - Widget label/name
  - `"tags"` - Widget tags
  - `"multiple_instances"` - Instance limit
  - `"preferred_position"` - Position preference
  - `"definition_uuid"` - UUID
  - `"updated_at"` - Last update timestamp (default)
- `order` (optional): `"asc"` or `"desc"` (default: desc)
- `page` (optional): Page number for pagination (default: 1)
- `per_page` (optional): Results per page (default: 10)

**Returns:**
```typescript
{
  custom_widgets: Array<{
    type: "custom_widget";
    widget_class_name: string;  // Usually "CustomWidget"
    label: string;  // Widget display name
    id: number;  // Widget definition ID
    tags: string;  // Comma-separated tags
    multiple_instances: number;  // 0=unlimited, 1=single per page
    preferred_position: number;  // Suggested position
    widget_definition_uuid: string;  // OID (deprecated field)
    definition_uuid: string;  // OID - USE THIS for adding to pages
    variables: Array<{
      slug: string;
      value: string;
      selected?: boolean;
    }>;
    sync: boolean;
    published: boolean;
  }>;
  meta: {
    total_entries: number;
    per_page: number;
    current_page: number;
    total_pages: number;
  };
}
```

**Important Notes:**
- **Only shows published widgets** - Use release tools to publish first
- `definition_uuid` is an OID (SHA hash), not a standard UUID format
- This is the identifier needed for `page-add-widgets` tool
- `widget_definition_uuid` is deprecated; use `definition_uuid` instead
- Empty result means no widgets are published yet
- `multiple_instances: 0` allows unlimited instances per page
- `multiple_instances: 1` restricts to single instance per page

**Examples:**

**Get all published widgets:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605
}

// Response:
{
  custom_widgets: [
    {
      type: "custom_widget",
      label: "Account Balance",
      id: 86713,
      definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      tags: "banking,account,balance,dashboard",
      multiple_instances: 1,
      variables: [],
      published: true
    },
    {
      label: "Quick Transfer",
      id: 86716,
      definition_uuid: "78d06422474244b364007bfc17f45f63be11c530",
      tags: "banking,transfer,payments,dashboard",
      ...
    }
  ],
  meta: { total_entries: 4, ... }
}
```

**Search for banking widgets:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  query: "banking",
  sort_by: "label",
  order: "asc"
}
```

**Get first page of widgets:**
```typescript
{
  platformSlug: "fed-team",
  siteId: 4605,
  per_page: 10,
  page: 1
}
```

## Complete Workflow Example

### Getting Widget UUIDs for Page Layout

**Scenario:** After publishing 4 banking widgets, you need their UUIDs to add them to the homepage.

**Step 1: Get published widgets**
```typescript
widget-get-custom-widgets({
  platformSlug: "fed-team",
  siteId: 4605
})
```

**Step 2: Extract definition_uuid values**
```json
{
  "custom_widgets": [
    {
      "label": "Account Balance",
      "definition_uuid": "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260"
    },
    {
      "label": "Quick Transfer",
      "definition_uuid": "78d06422474244b364007bfc17f45f63be11c530"
    },
    {
      "label": "Transaction List",
      "definition_uuid": "5b6925958f0c82370aef9fdf4b606dafcda674c3"
    },
    {
      "label": "Product Cards",
      "definition_uuid": "78986a7ae2c1264e5448bb3522ee5eee87312b98"
    }
  ]
}
```

**Step 3: Use UUIDs with page-add-widgets**
```typescript
page-add-widgets({
  platformSlug: "fed-team",
  siteId: 4605,
  pageId: 175255,
  widgets: [
    {
      type: "custom_widget",
      widget_definition_uuid: "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260",
      position: 0,
      column: 0,
      enabled: true,
      label: "Account Balance"
    },
    // ... more widgets
  ]
})
```

## Best Practices

1. **Always check published state** - This tool only shows published widgets
2. **Use definition_uuid** - It's the current field; `widget_definition_uuid` is deprecated
3. **Store UUIDs** - OIDs remain stable across republishing (unlike widget IDs)
4. **Filter with tags** - Use consistent tagging strategy for easier discovery
5. **Respect multiple_instances** - Check this before adding multiple copies to a page
6. **Search before creating** - Use `query` parameter to avoid duplicate widgets
7. **Paginate large lists** - Use `per_page` and `page` for sites with many widgets

## Understanding Widget UUIDs and Versioning

### UUID vs OID

**Format:**
- Modyo calls them "UUIDs" but they're actually OIDs (SHA-1 hashes)
- Format: 40 hexadecimal characters (e.g., `ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260`)
- Not RFC 4122 standard UUID format (no hyphens)
- Stable across republishing (unlike widget IDs which may change)

### Critical: Widget ID Changes After Publishing

**IMPORTANT**: When a widget is published in Modyo:

1. **ID Changes**: The widget `id` field changes because Modyo creates a new version
2. **UUID/OID Stable**: The `definition_uuid` (OID) remains constant across all versions
3. **Old Version Stored**: Previous version is archived for rollback/history
4. **Rollback Available**: Can revert to previous versions via Modyo UI

**Why This Matters:**
```typescript
// ❌ WRONG - Don't store or reference widgets by ID
const widgetId = 86713;
widget-definition-update({ widgetId, ... });  // May fail after publish

// ✅ CORRECT - Always use definition_uuid (OID) for references
const widgetUuid = "ac2fe2d381f5436e52b1cea8a37e0a8a2faf5260";
// Use UUID to identify widget across all versions
```

**Versioning Workflow:**
```
1. Create widget definition (id: 100, definition_uuid: "abc123...")
2. Edit widget (still id: 100, definition_uuid: "abc123...")
3. Publish via release → Creates version
   - Old version archived (id: 100, version: 1)
   - New published version (id: 101, definition_uuid: "abc123...")
4. Edit again (id: 101, definition_uuid: "abc123...")
5. Publish again → Creates another version
   - Version 1 archived (id: 100)
   - Version 2 archived (id: 101)
   - New published version (id: 102, definition_uuid: "abc123...")
```

**Rollback Behavior:**
- Can revert to version 1 (id: 100) or version 2 (id: 101) via Modyo UI
- After rollback, a new version is created with new ID
- `definition_uuid` always remains "abc123..." throughout all versions

**Why OIDs Matter:**
- ✅ Widget IDs change after every publish - don't rely on them
- ✅ OIDs (definition_uuid) remain constant - always use these
- ✅ Stable references across versions and republishing
- ✅ Used for syncing widgets across sites
- ✅ Required parameter for adding widgets to pages

**Best Practices:**
- ✅ Use `definition_uuid` for stable references across versions
- ✅ Fetch current widget info by UUID before operations
- ✅ Store UUIDs/OIDs in external systems, not IDs
- ❌ Don't hardcode widget IDs
- ❌ Don't assume IDs remain constant after publishing
- ❌ Don't use ID-based lookups in automated workflows

## Common Errors

**Empty custom_widgets array**
- No widgets have been published yet
- Solution: Use `release-create` to publish widget definitions

**"Widget definition uuid can't be blank"**
- Attempting to add widget without providing UUID
- Solution: Get UUID from this tool first

**Widget not appearing in list**
- Widget definition exists but not published
- Solution: Check `release-get-elements-to-publish` and create release

## Related Tools

- `release-create` - Publish widget definitions to make them available
- `release-get-elements-to-publish` - Check which widgets need publishing
- `page-add-widgets` - Add published widgets to pages using UUIDs
- `widget-definition-get` - View widget definition details (draft version)
- `widget-definitions-list` - List all widget definitions (draft and published)

## Editing Published Widgets

**Quick Reference**: To edit a widget that's already published and used on pages:

### 1. Find Widget UUID from Page

```typescript
const page = await page-get({ platformSlug, siteId, pageId });
const widget = page.widgets.find(w => w.label === "Widget Name");
const uuid = widget.definition_uuid;  // e.g., "bee3ee40972ffa9d8b44cabac65aaa618549e356"
```

### 2. Get Widget Definition ID (Not Custom Widget ID!)

**❌ WRONG** - Don't use `widget-get-custom-widgets`:
```typescript
// This returns custom widgets (published), but IDs won't work for editing
const customWidgets = await widget-get-custom-widgets({ platformSlug, siteId });
```

**✅ CORRECT** - Use `widget-definitions-list`:
```typescript
// This returns editable widget definitions with correct IDs
const definitions = await widget-definitions-list({ platformSlug, siteId, query: "" });
const widget = definitions.widget_definitions.find(w => w.uuid === uuid);
const widgetId = widget.id;  // This is the ID to use for editing!
```

### 3. Get and Update Widget

```typescript
// Get current code
const widget = await widget-definition-get({ platformSlug, siteId, widgetId });

// Update with new code
await widget-definition-update({
  platformSlug,
  siteId,
  widgetId,
  html: "<div>New HTML...</div>",
  css: ".new-styles { }",
  js: "console.log('Updated');"
});
```

### 4. Publish Changes

```typescript
// Get publishable elements
const elements = await release-get-elements-to-publish({ platformSlug, siteId });

// Find widget by UUID (NOT ID - ID may have changed!)
const widgetToPublish = elements.widgetDefinition.find(w => w.oid === uuid);

// Publish
await release-create({
  platformSlug,
  siteId,
  data: {
    widgetDefinition: [{ id: widgetToPublish.id, selected: true }]
  }
});
```

**📖 Full Guide**: See [Editing Published Widgets](../../docs/EDITING_PUBLISHED_WIDGETS.md) for complete documentation with troubleshooting and best practices.

## API References

- Admin API Widget Definitions: `/sites/{site_id}/widget_definitions` (GET) - **Use this for editing**
- Admin API Custom Widgets: `/sites/{site_id}/custom_widgets` (GET) - For published list only
- Query parameters: `query`, `sort_by`, `order`, `page`, `per_page`
- Documentation: https://docs.modyo.com/en/platform/channels/widgets.html
