Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation for customizing snap-in configuration page #63

Merged
merged 15 commits into from
Aug 14, 2024
2 changes: 1 addition & 1 deletion fern/docs/pages/references/inputs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ inputs:
- value-2
- value-3
is_required: true
default_value: value-1
default_value: [value-1]
ui:
display_name: Enum List Picker
```
226 changes: 226 additions & 0 deletions fern/docs/pages/references/snap-in-configuration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
# Customizing Snap-in Configuration Pages
codeon marked this conversation as resolved.
Show resolved Hide resolved

DevRev Snap-ins platform allows developers to define custom configuration pages for their Snap-ins. This feature provides flexibility in designing user-friendly and intuitive configuration experiences tailored to the specific needs of the Snap-in.
codeon marked this conversation as resolved.
Show resolved Hide resolved

## Why Customize Configuration Pages?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this heading, it's unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.


While the default configuration page automatically renders input fields for keyrings and inputs, there may be cases where a custom configuration page is more suitable:

- Improved User Experience: Developers can design the configuration page to provide a more intuitive and streamlined experience for users setting up the Snap-in.
codeon marked this conversation as resolved.
Show resolved Hide resolved
- Advanced Input Handling: Custom configuration pages enable developers to handle complex input scenarios, such as fetching data from external systems to populate dropdown options or validating user input.
- Branding and Styling: Developers can align the configuration page with their Snap-in's branding and style guidelines, ensuring a consistent look and feel.

## Defining Custom Configuration Pages
codeon marked this conversation as resolved.
Show resolved Hide resolved

To create a custom configuration page for a Snap-in, developers need to define the following in the Snap-in manifest:
codeon marked this conversation as resolved.
Show resolved Hide resolved

```yaml
snap_kit_actions:
- name: org_snap_kit_action
function: org_snap_in_configuration_handler
- name: user_snap_kit_action
function: user_snap_in_configuration_handler

functions:
- name: org_snap_in_configuration_handler
description: Handler for processing organization configuration options.
- name: user_snap_in_configuration_handler
description: Handler for processing user configuration options.
- name: config_initializer
description: Generates the initial configuration options for both organization and user.

configuration_handler:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having separate functions for each of these is a bit expensive. Let's combine these into a single function in our example.

organization:
initializer: config_initializer
snap_kit_action_name: org_snap_kit_action
user:
initializer: config_initializer
snap_kit_action_name: user_snap_kit_action
```

The `configuration_handler` section in the manifest connects the functions responsible for generating and processing the custom configuration page.

- `config_initializer`: This function generates the initial configuration options for both organization and user. It is called when the configuration page is first loaded.
codeon marked this conversation as resolved.
Show resolved Hide resolved
- `org_snap_in_configuration_handler`: This function processes the organization configuration options. It is triggered when actions are performed on the organization configuration snap-kit.
- `user_snap_in_configuration_handler`: This function processes the user configuration options. It is triggered when actions are performed on the user configuration snap-kit.

## Configuration Functions

The configuration functions should return a valid snap-kit JSON that defines the layout and elements of the custom configuration page. Here's an example of a snap-kit JSON:

```json
{
"snap_kit_body": {
"body": {
"snaps": [
{
"elements": [
{
"action_id": "user_snap_kit_action",
"action_type": "remote",
"elements": [
{
"element": {
"action_id": "select",
"action_type": "client",
"initial_selected_option": {
"text": {
"text": "Ticket",
"type": "plain_text"
},
"value": "ticket"
},
"options": [
{
"text": {
"text": "Ticket",
"type": "plain_text"
},
"value": "ticket"
},
{
"text": {
"text": "Conversation",
"type": "plain_text"
},
"value": "conversation"
}
],
"type": "static_select"
},
"type": "input_layout"
}
],
"submit_action": {
"action_id": "next",
"style": "primary",
"text": {
"text": "Next",
"type": "plain_text"
},
"type": "button",
"value": "next"
},
"type": "form"
}
],
"type": "card"
}
]
}
}
}
```

In this example, the snap-kit renders a dropdown select for choosing between "Ticket" and "Conversation," along with a "Next" button. When the "Next" button is clicked, the `user_snap_in_configuration_handler` function is invoked to process the user's selection.
codeon marked this conversation as resolved.
Show resolved Hide resolved
In the snap-kit action handler, the `event.payload.action.id` can be used to determine the form being submitted and call the snap-ins.update API to update the configuration.
codeon marked this conversation as resolved.
Show resolved Hide resolved

Certainly! Here's the updated documentation in Markdown format:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the following section a duplicate of the API spec? If so then it should be removed.

Copy link
Contributor Author

@codeon codeon Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make this API Beta. It is internal right now. I'll start that change and remove this section before merging this PR.


## Update Snap-in Inputs (BETA)

Updates the inputs of a snap-in based on the inputs defined in the snap-in configuration.

**Note: This endpoint is currently in BETA and may be subject to change in the future.**

### Endpoint

```
POST /internal/snap-ins.update
```

### Request Payload
codeon marked this conversation as resolved.
Show resolved Hide resolved

The request payload should be a JSON object with the following properties:

- `id` (string, required): The ID of the snap-in to update.
- `inputs_values` (object, required): An object containing the input values to update. The properties of this object should match the input names defined in the snap-in configuration.

Example payload:
```json
{
"id": "snap_in_id",
"inputs_values": {
"part_picker": "don:core:dvrv-us-1:devo/XXXX/product:XXXX",
"enum_list_picker": ["value-1", "value-2"]
}
}
```

In the example above, the `part_picker` and `enum_list_picker` are the input names defined in the snap-in configuration, and their corresponding values are provided in the `inputs_values` object.

### Response

#### Success Response

- Status Code: 200 OK
- Content-Type: application/json

Response Body:
```json
{
"data": {},
"message": "Snap-in updated successfully",
"success": true
}
```

#### Error Response

If an error occurs while updating the snap-in, the response will have the following format:

- Status Code: 4xx or 5xx
- Content-Type: application/json

Response Body:
```json
{
"data": {},
"message": "Failed to update the snap-in. Err: {error details}, Status: {status code}",
"success": false
}
```

### Example Usage
codeon marked this conversation as resolved.
Show resolved Hide resolved

Here's an example of how to use the `/internal/snap-ins.update` endpoint using the provided code segment:

```typescript
async updateSnapInInputs(snapin_id: string, inputs_values: Record<string, any>): Promise<HTTPResponse> {
const payload: Record<string, any> = {
id: snapin_id,
inputs_values,
};
return this.updateSnapInGlobalVariable(payload);
}

async updateSnapInGlobalVariable(payload: Record<string, any>): Promise<HTTPResponse> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: globalVariable as a term is not exposed to the external developers. Let's use inputs?

try {
await axios.post(`${this.endpoint}/internal/snap-ins.update`, payload, this.configs);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reminder to update this to use devrevSDK?

return { data: {}, message: 'Snap-in updated successfully', success: true };
} catch (error: any) {
if (error.response) {
const err = `Failed to update the snap-in. Err: ${JSON.stringify(error.response.data)}, Status: ${error.response.status}`;
return { ...defaultResponse, message: err };
} else {
return { ...defaultResponse, message: error.message };
}
}
}
```

In this example, the `updateSnapInInputs` function takes the `snapin_id` and `inputs_values` as parameters. The `inputs_values` object should contain the input names and their corresponding values as defined in the snap-in configuration.

The function constructs the payload object with the `snapin_id` and `inputs_values`, and then calls the `updateSnapInGlobalVariable` function to make the POST request to the `/internal/snap-ins.update` endpoint.

If the request is successful, it returns a success response with a status code of 200 and a message indicating that the snap-in was updated successfully.

If an error occurs, it catches the error and returns an error response with an appropriate status code and an error message containing the error details.

Please keep in mind that this endpoint is currently in BETA, and its functionality or parameters may change in future updates.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud - Should we have some sort of subscribe to beta changes button in our documentation which can help us keep track of who all external parties which are using a beta feature? It can help us in the future when we need to track down who all are depending on this feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally we should be doing this based on the endpoint and our logging. But I can put a note here.

codeon marked this conversation as resolved.
Show resolved Hide resolved

## Conclusion
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.


Customizing Snap-in configuration pages empowers developers to create tailored and user-friendly setup experiences. By defining the layout and elements of the configuration page using snap-kit JSON, developers can guide users through the configuration process, handle complex input scenarios, and ensure a seamless integration with their Snap-in's functionality.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant, remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.


For more details on the snap-kit JSON format and available elements, refer to the DevRev Snap-kit documentation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include hyperlink.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

109 changes: 109 additions & 0 deletions fern/docs/pages/retry-mechanism.mdx

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any external developers which are waiting for the event-retry documentation to become public? My suggestion would be to keep this particular documentation internal and let our main snap-ins like Email, Slack etc. onboard to this mechanism first to confirm that everything works and is stable in PROD.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, removed retries doc for now since we are also revamping the backend approach.

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Event Reliability in DevRev Snap-ins
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.


DevRev Snap-ins platform now offers enhanced event reliability features to ensure smooth and resilient event processing. This document provides an overview of these features and how developers can leverage them to build reliable Snap-ins.
codeon marked this conversation as resolved.
Show resolved Hide resolved

## Retryable Errors

Snap-ins can now define retryable errors using the `FunctionExecutionError` interface provided by the DevRev SDK. This allows the platform to automatically retry events that encounter intermittent or transient errors, improving overall reliability.

## Retry Configuration

Developers can configure the retry behavior of their Snap-in functions using the Snap-in manifest. The following options are available:

```yaml
functions:
- name: function_name
config:
runtime:
max_retries: 5 # number of retries before failing the event
min_interval: 10 # interval in seconds between each retry

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Let's use a more realistic value

Suggested change
min_interval: 10 # interval in seconds between each retry
min_interval: 120 # interval in seconds between each retry

```

- `max_retries`: Specifies the maximum number of retries before marking the event as failed.
codeon marked this conversation as resolved.
Show resolved Hide resolved
- `min_interval`: Specifies the minimum interval in seconds between each retry attempt. This interval may be adjusted based on the timeout of the corresponding function.

## Error Handling

The DevRev Snap-ins platform handles errors based on the ordering guarantees of the Snap-in function:
codeon marked this conversation as resolved.
Show resolved Hide resolved

For Snap-in functions with relaxed ordering, non-retryable errors will be marked as failed, and the error will be propagated to the DevRev platform for tracking. Retryable errors will be automatically retried based on the specified retry configuration. If the maximum number of retries is exhausted, the event will be moved to a dead-letter queue (DLQ) for further handling.
codeon marked this conversation as resolved.
Show resolved Hide resolved

## Error Interface

The DevRev SDK introduces the `FunctionExecutionError` type to represent errors returned from the Snap-in function's run function. Developers can use this type to provide additional error details and indicate whether an error is retryable.
codeon marked this conversation as resolved.
Show resolved Hide resolved

```typescript
class FunctionExecutionError extends Error {
/**
* Toggle to determine if the event should be retried or not. If not set or set to false,
* the event will not be retried.
*/
retry: boolean;

/**
* Whether to retry the event payload with updated metadata
* that platform provides. Useful when the event payload is
* not in a state to be directly processed, and may need new
* keyrings/service account tokens or new inputs.
*/
refresh?: boolean;

constructor(message: string, retry: boolean, refresh?: boolean) {
super(message);
this.retry = retry;
this.refresh = refresh;
}
}
```

## Example Usage

Here's an example of how to use the `FunctionExecutionError` in your Snap-in code:

```typescript
import { FunctionExecutionError } from '@devrev/typescript-sdk/dist/snap-ins/types';

export const run = async (events: any[]) => {
/*
Put your code here to handle the event.
*/
console.log('Events: ', JSON.stringify(events));

try {
// Your event processing logic here
// ...

// Retryable error
console.log('Retrying....');
const runtimeError = new FunctionExecutionError('Runtime Retryable Error', true, false);
throw runtimeError;

// Non-retryable error
// const runtimeError = new FunctionExecutionError("Runtime Non-Retryable Error", false, false);
// throw runtimeError;

} catch (error) {
if (error instanceof FunctionExecutionError) {
throw error;
} else {
// Handle other types of errors
// ...
}
}
};

export default run;
```

In this example, the Snap-in function's `run` method processes the events and can throw a `FunctionExecutionError` to indicate whether the error is retryable or not. The Snap-in platform will handle the error based on the `retry` and `refresh` properties set in the error object.

## Getting Started
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to near the beginning of the article.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved.


To start using the event reliability features in your Snap-ins, follow these steps:

1. Update your DevRev SDK to the latest version.
2. Define retryable errors using the `FunctionExecutionError` interface in your Snap-in code.
3. Configure the retry behavior in your Snap-in manifest.
4. Handle errors appropriately in your Snap-in function.

With these updates, your Snap-ins can leverage the enhanced event reliability features provided by the DevRev Snap-ins platform.
Loading