npm package: @swimlane/swimlane-element
Description: `SwimlaneElement` is a simple base class for creating Swimlane platform widgets using [lit-html](https://lit-html.polymer-project.org/) templating.
Author: Swimlane
Latest version: 2.8.0

# SwimlaneElement

`SwimlaneElement` is a simple base class for creating Swimlane platform widgets using [lit-html](https://lit-html.polymer-project.org/) templating.

## Building

Run `npm run build` to build SwimlaneElement. The build artifacts will be stored in the `build/` directory.

## Development server

Run `npm run start` to serve the demo.

## Release

- Checkout master (`git checkout master`)
- Pull master (`git pull`)
- Refresh node modules (`npm ci`)
- Examine log to determine next version (X.Y.Z)
- Run `git checkout -b release/X.Y.Z`
- Update version in `package.json`.
- Update changelog in `CHANGELOG.md`
- Run `git commit -am "(release): X.Y.Z"`
- Run `git tag X.Y.Z`
- Run `git push origin HEAD --tags`
- Run `npm run publish`
- Submit PR

## Overview

`LitElement` (https://lit-element.polymer-project.org/) is a webcomponent base class that uses `lit-html` (https://lit-html.polymer-project.org/) templating library.  `LitElement` (https://lit-element.polymer-project.org/) uses [lit-html](https://lit-html.polymer-project.org/) to render into the element's [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) and adds API to react to changes in properties.  

`SwimlaneElement` extends from `LitElement` to add API for interacting with records or reports in the Swimlane platform.

## Getting Started

```js
/**
 * Import `SwimlaneElement` class.
 * The `css` and `html` methods are also imported from `swimlane-element`.
 */
import { SwimlaneElement, css, html } from '@swimlane/swimlane-element@1';

/**
 * The `recordFrameTemplate` is a template function see templates below.
 */
import { recordFrameTemplate } from '@swimlane/swimlane-element@1/templates.js';

/**
 * A Swimlane widget is implemented as an anonymous class which extends the `SwimlaneElement` class.
 */
export default class extends SwimlaneElement {
  /**
   * The `styles()` getter is a static class getter, in other words, it is a property defined on the class constructor.
   * This style getter method does not have access to any properties stored in the objects.
   * This getter defines styles common to all instances of this widget.
   * Defining this in your widget is optional.
   */
  static get styles() {
    return [super.styles, css`
      .frame::after {
        content: "Record Output";
      }
    `];
  }

  /**
   * The `render` method is an instance method and, therefore, has access to properties  stored in the object (i.e. `record` and `report`, see properties below.
   * The render method is scheduled by `LitElement` Lifecycle events and must return a `lit-html` template.
   * Defining this method in your widget is required.
   */
  render() {
    return recordFrameTemplate(html`
      <pre>${JSON.stringify(this.record, undefined, 2)}</pre>
    `);
  }
}
```

### Properties

`LitElement` efficiently manages declared properties and attributes. By default `SwimlaneElement` declares `record` or `report` properties as well as the `'contextData'` property.  Documentation on how `LitElement` handles properties and attributes can be found [here](https://lit-element.polymer-project.org/guide/properties).

- `this.record` - Available to record widgets, an object containing key-value pairs for each field on the record. 
- `this.report` - Available to report widgets, an object containing `data`, `rawData`, and `query`.
- `this.contextData` - Available to both record and report widgets, an object containing data such as `application`, `currentUser`, `origin`, and `token`.

### Templates

To define a template for a `SwimlaneElement` component, write a render function that returns a `lit-html` template.  More details on writing render methods can be found in the documentation for [`LitElement`](https://lit-element.polymer-project.org/guide/templates) and [lit-html](https://lit-html.polymer-project.org/guide/template-reference).  The `swimlane-element` library includes predefined templates designed for the Swimlane platform.  These templates can be imported from `@swimlane/swimlane-element@1/templates.js`.

- `recordFrameTemplate` - A base template for rendering a frame on the record page.  This function takes as arguments a template to render inside the frame and an optional `rows` height value.  Without a defined `rows` value the frame will auto size to the content.
- `reportFrameTemplate` - A base template for rendering a frame on the dashboards.  This function takes as arguments a template to render inside the frame and an optional `rows` height value.  Without a defined `rows` value the frame will auto size to the content.

### Styles

As with `LitElement` there are "three main places in which you can define styles for your host element" <sup>[ref](https://lit-element.polymer-project.org/guide/styles#where)</sup>.  The two most common methods for `SwimlaneElements` will be to [Define styles in a static styles property](https://lit-element.polymer-project.org/guide/styles#static-styles) or [Define styles in a style element](https://lit-element.polymer-project.org/guide/styles#style-element).

### Events

Documentation on how to handle events in `LitElement` can be found [here](https://lit-element.polymer-project.org/guide/events).  `SwimlaneElement` adds the following methods for emitting Swimlane widget events:

#### Record Widget Methods

- `this.updateRecordValue(key, value)` : Available to record widgets. Updates record data by field key.
- `this.addComment(key, value)` : Available to record widgets. Adds a new comment by field key. Returns a Promise that resolves with the comment details or rejects with an error.
- `this.triggerIntegration(taskId)` : Available to record widgets. Triggers an integration. Returns a Promise that resolves when the integration completes or fails with an error.
- `this.triggerSave()` : Available to record widgets. Triggers record save on the record page. Returns a Promise that resolves when the record is saved or rejects with an error.
- `this.triggerButton(buttonId)` : Available to record widgets. Triggers the specified button on the record page. Returns a Promise that resolves when the playbook completes or fails with an error.
- `this.getFieldId(key)` : Returns the field ID for a given field key from the context data.

#### Navigation Methods

- `this.navigate(route, params)` : Available to both record and report widgets. Programmatically navigates to a route with optional query parameters. The `params` argument is an optional object with key-value pairs for query parameters.

#### Record Management Methods

- `this.openRecord(appId, recordId)` : Available to both record and report widgets. Opens a record in a drawer (same way that referenced records are opened on the record page). Returns a Promise that resolves with the opened record or null if the record couldn't be opened.
- `this.newRecord(appId)` : Available to both record and report widgets. Opens a "new record" drawer for the given application. Returns a Promise that resolves with the new record or null if the record couldn't be created.

#### Notification Methods

- `this.triggerNotification(type, title, message)` : Available to both record and report widgets. Triggers a native toast notification in the platform with the specified type ('success', 'error', 'info', 'warning'), title, and message.

#### Marketplace Methods

- `this.triggerMarketplaceInstall(type, name)` : Available to both record and report widgets. Triggers the marketplace install dialog for the given marketplace entity. The `type` parameter specifies the type of marketplace entity (component, template, playbook, connector). Returns a Promise that resolves with the installation result or rejects with an error.

#### Component Execution Methods

- `this.executeComponent(componentId, inputs, triggerName?)` : Available to both record and report widgets. Executes the component with the given ID and input parameters. The `inputs` parameter is an object with key-value pairs for component inputs. The optional `triggerName` parameter allows specifying a custom name for the component execution trigger. Returns a Promise that resolves with the outputs of the component execution or rejects with an error.

#### Hero AI Companion Methods

- `this.hero.companion.open()` : Opens the Hero AI companion sidebar. Returns a Promise that resolves when the companion is opened.
- `this.hero.companion.close()` : Closes the Hero AI companion sidebar. Returns a Promise that resolves when the companion is closed.
- `this.hero.companion.fullScreen()` : Opens the Hero AI companion in fullscreen mode. Returns a Promise that resolves when the companion is opened in fullscreen.
- `this.hero.companion.newConversation(options)` : Starts a new conversation with the Hero AI companion. Accepts an options object with configuration for the conversation. Returns a Promise that resolves when the new conversation is started.
- `this.hero.companion.setMessage(options)` : Sets a message in the Hero AI companion input field. Accepts an options object with `message` (required) and `autoSend` (optional, defaults to false). Returns a Promise that resolves when the message is set.
- `this.hero.sendMessage(request)` : Available to both record and report widgets. Sends a message to the LLM and receives responses. The `request` parameter is an LLMRequest object containing messages, temperature, and maxTokens. Returns a Promise that resolves with the LLM response message.
- `this.hero.sendMessageToAgent(request)` : Available to record widgets only. Sends a message to the Agent and returns the response. The `request` parameter is an AgentRequest object containing agentId, prompt, sessionId, and files. Returns a Promise that resolves with the CodeAgentQueryResponse from the API.

### Configuration Methods

- `this.setConfig(config, replaceAll)` : Sets or updates the widget configuration. If `replaceAll` is true, replaces the entire config; otherwise merges with existing config.

### Lifecycle

`LitElement` watches properties and attributes for changes and asynchronously renders the template to the element's [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).  Documentation of `LitElement` lifecycle methods and properties can be found [here](https://lit-element.polymer-project.org/guide/lifecycle).  In addition to the `HtmlElement` and `LitElement` lifecycle methods, `SwimlaneElement` adds the `resizedCallback` method.

- `resizedCallback` - This method (called whenever the element is resized) but default simply calls [`requestUpdate`](https://lit-element.polymer-project.org/guide/lifecycle#requestupdate).

## Examples

### Basic

```js
// SwimlaneElement and html are the basic required imports
import { SwimlaneElement, html } from '@swimlane/swimlane-element@1';

// Create and export a class definition for your widget that extends the SwimlaneElement base class
export default class extends SwimlaneElement {
  // The render callback renders your element's template.
  // It should always return the same template given the same properties and should not perform
  // any side effects such as setting properties or manipulating the DOM.
  render() {
    // Return the template using the html template tag.
    return html`
      <div>Hello world!</div>
    `;
  }
}
```

### Record data

```js
import { SwimlaneElement, html } from '@swimlane/swimlane-element@1';

export default class extends SwimlaneElement {
  // The render callback is called each time the record data changes.
  // lit-html is optimized for handling frequent updates and updating the DOM efficiently
  render() {
    return html`
      <div>
        Current count: ${this.record['count']}
      </div>
    `;
  }
}
```

### Handling events

```js
import { SwimlaneElement, html } from '@swimlane/swimlane-element@1';

export default class extends SwimlaneElement {
  render() {
    return html`
      <div>
        Current count: [${this.record['count']}]
        <!-- Use @[eventname] syntax to register inline event handlers -->
        <button @click=${() => this.updateRecordValue('count', this.record['count'] + 1)}>+</button>
        <!-- You can also pass a function reference directly. -->
        <button @click=${this._onDecrement}>-</button>
      </div>
    `;
  }

  _onDecrement() {
    this.updateRecordValue('count', this.record['count'] - 1)
  }
}
```

### Styles in a static styles property

```js
import { SwimlaneElement, html } from '@swimlane/swimlane-element@1';

export default class extends SwimlaneElement {
  /**
   * Styles should be added as a static getter. They are evaluated once, and then added
   * in the element's shadow dom.
   */
  static get styles() {
    return css`
      :host {
        display: block;
      }
      .message {
        color: blue;
      }
    `;
  }

  render() {
    return html`
      <div class="message">
        Current count: ${this.record['count']}
      </div>
    `;
  }
}
```

### Swimlane styles

```js
import { SwimlaneElement, html } from '@swimlane/swimlane-element@1';
import { recordFrameTemplate } from '@swimlane/swimlane-element@1/templates.js';

export default class extends SwimlaneElement {
  /**
   * The styles getter may return a array.
   * Add `super.styles` to get swimlane default styles.
   * Overide the `.frame::after` style to set a label for the frame.
   */
  static get styles() {
    return [super.styles, css`
      :host {
        display: block;
      }
      .message {
        color: blue;
      }
      .frame::after {
        content: "Current Count";
      }
    `];
  }

  /**
   * Wrap the template in `recordFrameTemplate` function to add a frame.
   * The seoncd argument (optional) is the row count height.
   */
  render() {
    return recordFrameTemplate(html`
      <div class="message">
        ${this.record['count']}
      </div>
    `, 2);
  }
}
```

### Styles in a style element.

```js
import { SwimlaneElement, html } from '@swimlane/swimlane-element@1';

export default class extends SwimlaneElement {
  render() {
    const color = this.record['count'] > 10 ? 'red' : 'blue';
    return html`
      <-- styles defined here are dynamic, and will update when properties update.
      <style>
        .message {
          color: ${color};
        }
      </style>
      <div class="message">
        Current count: ${this.record['count']}
      </div>
    `;
  }
}
```

### Full Demo

```js
import { SwimlaneElement, css, html } from '@swimlane/swimlane-element@1';
import { recordFrameTemplate } from '@swimlane/swimlane-element@1/templates.js';

export default class extends SwimlaneElement {
  static get styles() {
    return [super.styles, css`
      :host {
        text-align: center;
      }
      .frame::after {
        content: "Current Count";
      }
      button {
        font-size: xx-large;
        margin-top: 10px;
        height: 60px;
        width: 60px;
        border-radius: 5px;
        background-color: #ffbb47;
        color: #07080b;
        bordeR: 0;
      }
      .message {
        font-size: xx-large;
      }
    `];
  }

  render() {
    const color = this.record['count'] > 10 ? '#FF4514' : '#1483FF';
    return recordFrameTemplate(html`
      <style>
        .message {
          color: ${color};
        }
      </style>
      <div>
        <div class="message">
          ${this.record['count']}
        </div>
        <button @click=${this._onIncrement}>+</button>
        <button @click=${this._onDecrement}>-</button>
      </div>
    `, 2);
  }

  _onIncrement() {
    this.updateRecordValue('count', this.record['count'] + 1)
  }

  _onDecrement() {
    this.updateRecordValue('count', this.record['count'] - 1)
  }
}
```

## Credits

`SwimlaneElement` is a [Swimlane](https://swimlane.com) open-source project; we believe in giving back to the open-source community by sharing some of the projects we build for our application. Swimlane is an automated cyber security operations and incident response platform that enables cyber security teams to leverage threat intelligence, speed up incident response and automate security operations.