Comment développer un plugin DocSpace : tutoriel complet étape par étape
Dans un monde où la vitesse et la collaboration sont essentielles, les outils de productivité doivent suivre. Les plugins DocSpace offrent un moyen moderne d’améliorer la façon dont les utilisateurs gèrent et interagissent avec les documents. Dans ce guide, nous vous expliquons comment créer votre propre plugin DocSpace à l’aide d’exemples réels tirés de nos échantillons de plugins officiels.
À propos de SDK de plugins de ONLYOFFICE DocSpace
Le SDK de plugins de ONLYOFFICE DocSpace est un package npm basé sur des moteurs TypeScript qui fournit des interfaces vous permettant de créer vos propres plugins et de les intégrer dans DocSpace. Le cycle de développement des plugins comprend la planification, le développement, les tests et l’utilisation.
Pour illustrer l’utilisation de notre SDK de plugins, nous avons créé un référentiel avec des exemples de plugins. Nous allons nous plonger dans le processus complet de développement d’un plugin en nous basant sur nos exemples de plugins.
Planification
Définissez l’objectif du plugin, réfléchissez à l’endroit où vous y accéderez et aux services tiers que vous devez connecter.
Étape 1. Installez tous les paquets et programmes nécessaires
- ONLYOFFICE DocSpace on-premises.
- @onlyoffice/docspace-plugin-sdk paquet npm
Pour installer globalement le paquet npm @onlyoffice/docspace-plugin-sdk, utilisez la commande suivante :
npm i -g @onlyoffice/docspace-plugin-sdk
Étape 2. Concevez le fonctionnement de votre plugin
Choisissez le service qui vous permet d’ajouter les fonctionnalités nécessaires à votre espace documentaire.
Par exemple, dans nos exemples de plugins, nous utilisons :
- AssemblyAI pour convertir en texte la parole contenue dans les fichiers audio et vidéo ;
- ConvertAPI pour convertir des documents texte, des feuilles de calcul, des présentations et des formulaires en PDF ;
- Draw.io pour créer, éditer et insérer des diagrammes de qualité professionnelle.
Remarque ! Assurez-vous que la documentation du service est disponible, vérifiez sa licence, la disponibilité des méthodes API, etc. Pour certains services, l’utilisateur doit obtenir une clé API pour commencer à utiliser le plugin.
Réfléchissez à l’endroit où implémenter le plugin, à sa structure, à la manière dont l’utilisateur interagira avec les composants du plugin, etc. En fonction de ces informations, dressez une liste des types de plugins et des éléments requis. Pour plus d’informations, lisez les sections Types de plugins et Éléments de plugins de la documentation du SDK des plugins.
Par exemple, pour le plugin Saisie vocale, nous utilisons les interfaces de plugin suivantes :
- IPlugin. Nécessaire pour chaque plugin. Il contient la variable PluginStatus du plugin, utilisée pour intégrer le plugin dans le DocSpace.
- ApiPlugin. Nécessaire car nous mettons en œuvre un service tiers.
- ISettingsPlugin et ISettings. Utilisés pour ajouter un bloc de paramètres pour la configuration du plugin. Les utilisateurs accèderont à ce bloc à partir de Paramètres -> Intégration -> Plugins pour ajuster les paramètres du plugin.
- IContextMenuPlugin and IContextMenuItem. Utilisés pour mettre en œuvre une action du menu contextuel. Dans le plugin Saisie vocale, il sera disponible pour les fichiers vidéo et audio, ce qui permettra aux utilisateurs de convertir le contenu en texte.
La liste des interfaces peut être plus longue. Par exemple, dans le plugin draw\.io :
- IMainButtonPlugin et IMainButtonItem. Utilisés pour mettre en œuvre l’action du bouton principal. Dans le plugin draw\.io, nous utilisons le bouton Action -> Plus d’éléments de menu dans la section Mes documents ou dans la salle sélectionnée pour créer des diagrammes draw\.io.
- IFilePlugin et IFileItem. Utilisés pour interagir avec les types de fichiers spécifiés. Dans ce cas, avec les fichiers .drawio.
Trouvez la structure du plugin. Tous les fichiers nécessaires sont décrits ici. Tout le reste peut être organisé comme vous le souhaitez. Par exemple, dans le plugin draw\.io, nous avons placé le code pour chaque type de plugin dans des dossiers séparés, alors que dans le plugin Saisie vocale ce code est placé dans le dossier src.
Choisissez un nom pour votre plugin et écrivez-en une description.
Développement du plugin
Maintenant que tout le travail de préparation est fait, vous pouvez commencer à développer votre plugin.
Étape 1. Créez un modèle de plugin
Créez un modèle de plugin et configurez ses paramètres qui seront affichés dans les paramètres du plugin DocSpace :
Pour créer un modèle de plugin, ouvrez le terminal et exécutez la commande npx suivante :
npx create-docspace-plugin
Si la commande npx n’est pas disponible, installez le paquet npm @onlyoffice/docspace-plugin-sdk à l’aide de la commande suivante :
npm i -g @onlyoffice/docspace-plugin-sdk
Configurez le plugin dans le terminal en spécifiant les paramètres dans la boîte de dialogue. Tous les paramètres sont décrits ici.
Pour le plugin Saisie vocale, vous pouvez utiliser les valeurs suivantes :
Vous pouvez modifier tous les paramètres spécifiés ultérieurement dans le fichier package.json.
Vous pouvez également créer un plugin dans n’importe quel projet en ajoutant le paquet npm @onlyoffice/docspace-plugin-sdk comme dépendance et en spécifiant tous les champs nécessaires dans le fichier package.json.
Étape 2. Configurez le point d’entrée du plugin
Le index.ts du plugin index.ts sera créé automatiquement dans le dossier src lors de l’étape de création du modèle. Ce fichier est nécessaire.
Ce fichier contient toutes les méthodes de base des types de plugins que vous avez sélectionnés à l’étape précédente. Vous pouvez modifier ce fichier à tout moment.
Si vous créez un plugin vous-même, sans modèle, pour le point d’entrée du plugin, vous pouvez utiliser le code de nos exemples de plugins prêts à l’emploi. Il fonctionnera parfaitement.
Étape 3. Ajoutez les icônes du plugin
Créez le dossier assets dans le dossier racine du plugin et ajoutez-y toutes les icônes du plugin. Le nombre d’icônes et leur taille dépendent des types de plugins que vous mettez en œuvre. Pour le plugin Saisie vocale, nous avons besoin des icônes suivantes :
- Le type de plugin par défaut nécessite une image de logo. Il est égal au paramètre logo du fichier package.json. Le logo sera affiché dans les paramètres du plugin DocSpace. La taille de l’icône requise est de 48×48 px. Sinon, elle sera compressée à cette taille.
- Le plugin du menu contextuel utilise une icône sur le bouton Convertir en texte. La taille requise de l’icône est de 16×16 px. Sinon, elle sera compressée à cette taille.
Cette icône peut également être utilisée pour l’icône du bouton principal. Par exemple, dans le plugin draw\.io, la même icône est utilisée pour le menu contextuel et le bouton principal.
Le plugin draw\.io utilise également l’icône de fichier spécifique près des fichiers .drawio, qui sont créés avec le type de plugin de fichier. La taille d’icône préférée pour le format de table est de 32×32 px.
Étape 4. Configurez les éléments d’interface du plugin
Par exemple, le plugin draw\.io contient deux éléments principaux de l’interface utilisateur – la fenêtre modale et l’éditeur de diagramme. Créez les fichiers de configuration de chaque élément. Pour plus de commodité, vous pouvez placer ces fichiers dans un dossier DrawIO séparé.
Dans le fichier Dialog.ts, configurez les paramètres de la fenêtre modale. Spécifiez le composant IFrame UI qui est utilisé pour intégrer le site web draw\.io dans une fenêtre modale :
export const frameProps: IFrame = {
width: "100%",
height: "100%",
name: "test-drawio",
src: "",
}
Créez le conteneur IBox pour y ajouter l’iframe :
const body: IBox = {
widthProp: "100%",
heightProp: "100%",
children: [
{
component: Components.iFrame,
props: frameProps,
},
],
}
Configurez les propriétés de la fenêtre modale :
export const drawIoModalDialogProps: IModalDialog = {
dialogHeader: "",
dialogBody: body,
displayType: ModalDisplayType.modal,
fullScreen: true,
onClose: () => {
const message: IMessage = {
actions: [Actions.closeModal],
}
return message
},
onLoad: async () => {
return {
newDialogHeader: drawIoModalDialogProps.dialogHeader || "",
newDialogBody: drawIoModalDialogProps.dialogBody,
}
},
autoMaxHeight: true,
autoMaxWidth: true,
Dans le fichier Editor.ts, configurez l’éditeur de diagramme. Créez la fonction DiagramEditor avec les paramètres suivants :
Paramètre | Type | Exemple | Description |
ui | string | “default” | Définit le thème de l’interface utilisateur de l’éditeur. |
dark | string | “auto” | Définit le thème sombre de l’éditeur. |
off | boolean | false | Spécifie si le mode hors ligne est actif ou non. |
lib | boolean | false | Spécifie si les bibliothèques sont activées ou non. |
lang | string | “auto” | Définit la langue de l’éditeur. |
url | string | `https://embed.diagrams.net` | Définit l’URL de l’éditeur. |
showSaveButton | boolean | true | Spécifie si le bouton **Save** sera affiché dans l’éditeur. |
Spécifiez ensuite des méthodes pour travailler avec des diagrammes :
Méthode | Description |
startEditing | Démarre l’éditeur avec les données fournies. |
getData | Renvoie les données du diagramme. |
getTitle | Renvoie le titre du diagramme. |
getFormat | Renvoie le format du diagramme. |
getFrameId | Renvoie l’identifiant du cadre de l’éditeur. |
getFrameUrl | Renvoie l’URL de l’iframe. |
handleMessage | Traite le message donné. |
initializeEditor | Affiche le message de *chargement* à l’éditeur. |
save | Enregistre les données fournies. |
Le code complet de *DiagramEditor* est disponible ici.
Étape 5. Créez des types de plugins
Maintenant que le plugin par défaut est prêt, vous pouvez commencer à coder d’autres types de plugins.
Chaque type de plugin possède des éléments de plugin spécifiques. Définissez l’élément du menu contextuel qui s’affichera lorsque vous ferez un clic droit sur les fichiers audio ou vidéo :
export const contextMenuItem: IContextMenuItem = {
key: "speech-to-text-context-menu-item",
label: "Convert to text",
icon: "speech-to-text-16.png",
onClick: assemblyAI.speechToText,
fileType: [FilesType.video],
withActiveItem: true,
}
Vous pouvez ajouter d’autres types de plugins. Par exemple, le plugin draw\.io est accessible depuis le menu du bouton principal, nous devons donc spécifier l’élément du bouton principal :
const mainButtonItem: IMainButtonItem = {
key: "draw-io-main-button-item",
label: "Draw.io",
icon: "drawio.png",
onClick: (id: number) => {
drawIo.setCurrentFolderId(id)
const message: IMessage = {
actions: [Actions.showCreateDialogModal],
createDialogProps: {
title: "Create diagram",
startValue: "New diagram",
visible: true,
isCreateDialog: true,
extension: ".drawio",
onSave: async (e: any, value: string) => {
await drawIo.createNewFile(value)
},
onCancel: (e: any) => {
drawIo.setCurrentFolderId(null)
},
onClose: (e: any) => {
drawIo.setCurrentFolderId(null)
},
},
}
return message
},
// items: [createItem],
}
Lorsque vous cliquez sur le bouton principal, une fenêtre modale apparaît dans laquelle vous pouvez saisir le nom du diagramme et ouvrir un fichier .drawio vide.
Pour le plugin draw\.io, vous devez également configurer le type de plugin de fichier qui fonctionne lorsque l’utilisateur ouvre le fichier .drawio spécifique :
Définissez l’élément de fichier qui est représenté sous la forme d’un fichier portant l’extension spécifique (.drawio) et l’icône :
export const drawIoItem: IFileItem = {
extension: ".drawio",
fileTypeName: "Diagram",
fileRowIcon: "drawio-32.svg",
fileTileIcon: "drawio-32.svg",
devices: [Devices.desktop],
onClick,
}
Définissez l’événement onClick qui exécutera la méthode editDiagram chaque fois que le fichier .drawio sera ouvert :
const onClick = async (item: File) => {
return await drawIo.editDiagram(item.id)
}
Étape 6. Créez le type de plugin de paramétrage
Configurez le type de plugin des paramètres pour fournir aux utilisateurs les paramètres de l’administrateur.
Créez un conteneur dans lequel les paramètres du plugin seront placés :
const descriptionText: TextGroup = {
component: Components.text,
props: {
text: "To generate API token visit https://www.assemblyai.com",
color: "#A3A9AE",
fontSize: "12px",
fontWeight: 400,
lineHeight: "16px",
},
}
const descGroup: BoxGroup = {
component: Components.box,
props: {children: [descriptionText]},
}
const parentBox: IBox = {
displayProp: "flex",
flexDirection: "column",
// marginProp: "16px 0 0 0",
children: [tokenGroup, descGroup],
}
Dans la description des paramètres, indiquez qu’il est nécessaire de générer un jeton API pour pouvoir travailler avec le plugin.
Configurez les paramètres de l’administrateur avec l’objet ISettings :
const adminSettings: ISettings = {
settings: parentBox,
saveButton: userButtonComponent,
onLoad: async () => {
assemblyAI.fetchAPIToken()
tokenInput.value = assemblyAI.apiToken
if (!assemblyAI.apiToken) {
return {
settings: parentBox,
}
}
plugin.setAdminPluginSettings(adminSettings)
return {settings: parentBox}
}
Spécifiez l’événement onLoad qui définit les paramètres du plugin qui seront affichés lorsque le bloc settins est chargé.
Chaque élément de réglage est déterminé dans des fichiers séparés (boutons, jetons).
Étape 7. Créez le fichier de code principal du plugin
Créez un fichier dans le dossier src avec le code principal du plugin. Ce fichier est obligatoire. Reportez-vous à la documentation d’un service tiers pour écrire ce code.
Voyons comment le fichier AssemblyAI.ts est organisé en détail :
Définissez la classe AssemblyAI avec toutes les variables et méthodes nécessaires :
- Variables et leur description :
apiURL
Définit l’URL de l’API.
apiURL = ""
currentFileId
Définit l’ID du fichier actuel.
const currentFileId: numbernull | number = null
apiToken
Définit le jeton de l’API.
apiToken = ""
- Méthodes et leur description :
createAPIUrl
Crée l’URL de l’API.
createAPIUrl = () => {
const api = plugin.getAPI()
this.apiURL = api.origin.replace(/\/+$/, "")
const params = [api.proxy, api.prefix]
if (this.apiURL) {
for (const part of params) {
if (!part) {
continue
}
const newPart = part.trim().replace(/^\/+/, "")
if (newPart) {
if (this.apiURL.length !== 0 && this.apiURL[this.apiURL.length - 1] === "/") {
this.apiURL += newPart
} else {
this.apiURL += `/${newPart}`
}
}
}
}
}
setAPIUrl
Définit l’URL de l’API.
setAPIUrl = (url: string) => {
this.apiURL = url
}
getAPIUrl
Définit l’URL de l’API.
getAPIUrl = () => {
return this.apiURL
}
setAPIToken
Définit le jeton API.
setAPIToken = (apiToken: string) => {
this.apiToken = apiToken
}
getAPIToken
Renvoie le code API.
getAPIToken = () => {
return this.apiToken
}
fetchAPIToken
Récupère le jeton de l’API.
fetchAPIToken = async () => {
const apiToken = localStorage.getItem("speech-to-text-api-token")
if (!apiToken) {
return
}
this.setAPIToken(apiToken)
plugin.updateStatus(PluginStatus.active)
}
saveAPIToken
Enregistre le jeton API.
saveAPIToken = (apiToken: string) => {
localStorage.setItem("speech-to-text-api-token", apiToken)
let status
if (apiToken) {
status = PluginStatus.active
} else {
status = PluginStatus.hide
}
plugin.updateStatus(status)
}
setCurrentFileId
Définit l’ID du fichier en cours.
setCurrentFileId = (id: number | null) => {
this.currentFileId = id
}
uploadFile
Charge un fichier qui sera transcrit.
uploadFile = async (apiToken: string, path: string, data: Blob) => {
console.log(`Uploading file: ${path}`)
const url = "https://api.assemblyai.com/v2/upload"
try {
const response = await fetch(url, {
method: "POST",
body: data,
headers: {
"Content-Type": "application/octet-stream",
"Authorization": apiToken,
},
})
if (response.status === 200) {
const responseData = await response.json()
return responseData["upload_url"]
}
console.error(`Error: ${response.status} - ${response.statusText}`)
return null
} catch (error) {
console.error(`Error: ${error}`)
return null
}
}
transcribeAudio
Transcrit le fichier audio.
transcribeAudio = async (apiToken: string, audioUrl: string) => {
console.log("Transcribing audio... This might take a moment.")
const headers = {
"authorization": apiToken,
"content-type": "application/json",
}
const response = await fetch("https://api.assemblyai.com/v2/transcript", {
method: "POST",
body: JSON.stringify({audioUrl}),
headers,
})
const responseData = await response.json()
const transcriptId = responseData.id
const pollingEndpoint = `https://api.assemblyai.com/v2/transcript/${transcriptId}`
while (true) {
const pollingResponse = await fetch(pollingEndpoint, {headers})
const transcriptionResult = await pollingResponse.json()
if (transcriptionResult.status === "completed") {
return transcriptionResult
} else if (transcriptionResult.status === "error") {
throw new Error(`Transcription failed: ${transcriptionResult.error}`)
} else {
await new Promise((resolve) => {
setTimeout(resolve, 3000)
})
}
}
}
speechToText
Implémente la fonctionnalité du plugin.
speechToText = async (id: number) => {
if (!this.apiToken) {
return
}
this.setCurrentFileId(null)
if (!this.apiURL) {
this.createAPIUrl()
}
const response = await fetch(`${this.apiURL}/files/file/${id}`)
const data = await response.json()
const {viewUrl, title, folderId, fileExst} = data.response
const file = await fetch(viewUrl)
const fileBlob = await file.blob()
const uploadUrl = await this.uploadFile(this.apiToken, viewUrl, fileBlob)
const transcript = await this.transcribeAudio(this.apiToken, uploadUrl)
const blob = new Blob([transcript.text], {
type: "text/plain;charset=UTF-8",
})
const newFile = new File([blob], "blob", {
type: "",
lastModified: Date.now(),
})
const formData = new FormData()
formData.append("file", newFile)
const newTitle = `${title.replaceAll(fileExst, "")} text`
try {
const sessionRes = await fetch(
`${this.apiURL}/files/${folderId}/upload/create_session`,
{
method: "POST",
headers: {
"Content-Type": "application/json;charset=utf-8",
},
body: JSON.stringify({
createOn: new Date(),
fileName: `${newTitle}.txt`,
fileSize: newFile.size,
relativePath: "",
}),
},
)
const response = await sessionRes.json()
const sessionData = response.response.data
const data = await fetch(`${sessionData.location}`, {
method: "POST",
body: formData,
})
const jsonData = await data.json()
const {id: fileId} = jsonData.data
return fileId
} catch (e) {
console.log(e)
}
return {
actions: [Actions.showToast],
toastProps: [{type: ToastType.success, title: ""}],
} as IMessage
}
Déclarez l’instance de la classe AssemblyAI :
const assemblyAI = new AssemblyAI()
Exportez l’instance de plugin créée :
export default assemblyAI
Tests
Pour vérifier la fonctionnalité du plugin et corriger les éventuels bogues, testez le plugin :
- Construisez le plugin préparé en suivant les instructions ici
Le dossier dist sera créé dans le dossier racine du plugin et l’archive du plugin y sera placée. Cette archive est le plugin complet qui peut être téléchargé sur DocSpace.
- Téléchargez votre plugin sur DocSpace et testez minutieusement son apparence et sa fonctionnalité.
Veuillez noter que vous ne pouvez télécharger vos propres plugins que dans la version serveur de DocSpace.
Si des bogues apparaissent, corrigez le code source de votre plugin et répétez la procédure de construction et de test.
Maintenant que votre plugin est testé et fonctionne correctement, vous pouvez l’ajouter à la version serveur de DocSpace et commencer à l’utiliser.
Le plugin DocSpace offre une approche puissante et conviviale de la gestion des documents et de la collaboration. En s’intégrant aux plateformes préférées des utilisateurs, il élimine les obstacles courants et améliore la productivité à travers différents flux de travail. Si vous avez des questions sur les plugins DocSpace, n’hésitez pas à les poser à nos développeurs sur le forum ONLYOFFICE (inscription requise). Vous pouvez également demander une fonctionnalité ou signaler un bug en postant un problème sur GitHub ou en partageant vos plugins DocSpace avec nous et d’autres utilisateurs. Nous vous souhaitons bonne chance dans vos projets exploratoires !
Créez votre compte ONLYOFFICE gratuit
Affichez, modifiez et coéditez des documents texte, feuilles de calcul, diapositives, formulaires et fichiers PDF en ligne.