Contact your CSM or email support@cinode.com for more information regarding app extensions.
API and admin permission level is required in Cinode to set up this integration.
Why UI App Extensions?
Cinode Extensions empower developers to expand the capabilities of the Cinode platform by introducing interactive features, such as custom menu actions and tailored data views. These extensions are designed to seamlessly integrate with third-party platforms, enabling the creation of dynamic workflows and interfaces that streamline processes and enhance productivity.
With Cinode Extensions, businesses can embed content and functionality directly from external SaaS applications, allowing users to access and interact with the tools and data they need without leaving the Cinode environment. This deep integration not only optimizes day-to-day operations but also improves visibility into critical business processes, enabling teams to work more efficiently and make data-driven decisions with ease.
What UI App Extensions does
1. Extendability:
- Seamlessly add custom tables or visual elements to Cinode views, tailored to your specific business needs.
- Design customised menu actions or interfaces to integrate directly with external platforms, creating a unified workflow.
- Ensure a global user experience by supporting translations for your extensions, adapting to different languages and regions seamlessly.
2. Efficiency:
- Save time by making key data visible within Cinode and enabling users to take necessary actions with a single click—eliminating the need to switch between tabs and systems.
- Streamline processes by centralising critical operations within Cinode's interface.
3. Modular:
- Trigger custom fields and forms through extensions to collect essential data efficiently.
- Ensure the right data is displayed in the right place by passing relevant information to your backend systems.
Extendable entities
The Cinode UI Extensions provide customisation capabilities to enhance the user experience through panels and buttons added to the following extendable entities:
1. Customer:
- Add customised views and functionalities related to customer data directly within the Cinode interface.
2. Project:
- Tailor project-related interactions and visual elements to meet specific business workflows.
3. Candidate:
- Extend candidate profiles with additional actions or panels to manage recruitment processes seamlessly.
4. Subcontractor:
- Incorporate specific subcontractor details or integrations that streamline operations involving external consultants or vendors.
Available UI Actions and Panels
1. Custom Panels:
- Add dedicated sections or tabs to display specific data or integrations related to an entity.
- Panels can host information fetched from third-party platforms or calculated data, such as analytics or KPIs.
2. Action Buttons:
- Create buttons that trigger specific workflows or actions directly from the UI.
3. Dynamic Modals:
- Add modals to collect or display information on-demand.
- These modals can interact with external APIs, ensuring real-time data exchange.
Use Cases
External Documents and Contracts: Display essential business documents, such as contracts or agreements, directly within the customer view, allowing for quick and easy access.
Third-Party Integrations: Connect with external platforms to fetch, display, and sync critical business data, ensuring all information is accessible in one place.
Call Response Sheets: Enhance sales calls by using a custom button to open a modal within Cinode, guiding your sales team to input data exactly as needed for consistency and accuracy.
How to get started with UI App Extensions
Register an AppMarket app in Cinode,
Administration > Integrations > Apps > Registration
.Implement the OAuth flow and install the app into your Cinode company.
Declare an extension in your app's extension configuration,
.. > Registration > "Your App" > Extensibility
. The configuration structure declares what extension points you want to extend, and how they are extended.Implement the extension callback HTTP endpoint in your app.
Highly recommended: Implement request signature verification.
Read more in the documentation.
Example Extension
This example demonstrates a basic UI extension featuring a table panel and a form modal. The extension integrates with a document management system, enabling users to review and add documents related to a project. Users can either input a direct link to a document or complete a predefined form to populate a document template. To enhance client engagement, this scenario includes a process for the sales team to conduct follow-up calls to ensure customer satisfaction.
We will showcase the UI both visually, with pictures, and technically, with accompanying code snippets, to provide a clear understanding of the implementation.
For the example above, we will need a JSON schema to define the extension, specifying its placement within Cinode and the available user actions. Additionally, we will require an endpoint to handle user interactions from the Cinode app, including generating the modal, fetching documents, and adding new documents.
Extension JSON Schema
Extension JSON Schema
{
"ui": {
"project": {
"menu": [],
"panels": {
"overview": [
{
"$type": "table",
"label": {
"en": "Documents",
"sv": "Dokument"
},
"description": {
"en": "List of project documents",
"sv": "Lista över projektdokument"
},
"name": "project-documents",
"dataSource": {
"$type": "data",
"name": "fetch-project-documents",
"dataUrl": "https://example.com/api/documents"
},
"primaryAction": {
"label": {
"en": "Add document",
"sv": "Lägg till dokument"
},
"name": "add-document",
"icon": "add",
"style": "positive",
"action": {
"$type": "form",
"name": "add-document",
"formUrl": "https://example.com/api/documents/form",
"submitUrl": "https://example.com/api/documents/add"
}
},
"itemActions": []
}
]
}
}
}
}
We have defined three endpoints in our extension schema: one for fetching documents, one for the add documents form and another for submitting and adding a new document. Below are two basic Node.js implementations to illustrate how this could work server-side. These examples assume that essential tasks like request signature verification and authentication are already handled.
listDocuments.js
listDocuments.js
const fastify = require('fastify')({ logger: false });
const documentsByCustomerId = {
123: [
{
name: "Document 1",
description: "This is the first document",
type: "pdf",
createdDate: "2022-01-01",
author: "John Locke",
},
],
// ...
};
fastify.post('/documents', async (request, reply) => {
// Get the company ID from the headers
const companyId = request.headers['x-cinode-company-id'];
// Get the customer ID from the context
const customerId = request.body.context.customer.id;
// Get the documents for the customer
const documents = documentsByCustomerId[customerId] || [];
// Format the documents
const formattedDocuments = documents.map((document) => ({
name: { value: document.name },
description: { value: document.description },
type: { value: document.type },
createdDate: { value: document.createdDate },
author: { value: document.author },
}));
// Return the response
return {
data: {
properties: {
name: {
label: {
en: "Name",
sv: "Namn",
}
},
description: {
label: {
en: "Description",
sv: "Beskrivning",
}
},
type: {
label: {
en: "Type",
sv: "Typ",
}
},
createdDate: {
label: {
en: "Created Date",
sv: "Skapat Datum",
}
},
author: {
label: {
en: "Author",
sv: "Författare",
}
},
},
values: formattedDocuments,
},
};
});
addDocumentForm.js
addDocumentForm.js
const fastify = require('fastify')({ logger: false });
fastify.get("/documents/form", async (request, reply) => {
const form = {
title: "Add a new document",
description: "Fill out the form below to add a new document.",
form: {},
rows: [],
};
// Add the type element
const typeElement = {
$type: "select",
label: "Type",
required: true,
values: [
{
label: "General",
value: "general"
},
{
label: "Contract",
value: "contract"
},
{
label: "Customer Satisfaction",
value: "customer-satisfaction"
},
],
};
form.form.type = typeElement;
form.rows.push({ elements: ["type"] });
// Add the satisfaction element
const satisfactionElement = {
$type: "input",
label: "Overall Satisfaction Rating",
required: true,
placeholder: "1-10",
};
form.form.satisfaction = satisfactionElement;
form.rows.push({ elements: ["satisfaction"] });
// Keep adding elements
// ...
// Return the form
return form;
});
To handle conditionally showing input fields depending on the document type one may use the dependsOn property in each form element.