Come sviluppare un plugin per DocSpace: tutorial completo passo dopo passo

21 maggio 2025Da Alice

In un mondo in cui velocità e collaborazione sono tutto, gli strumenti di produttività devono tenere il passo. I plugin di DocSpace offrono un modo moderno per migliorare il modo in cui gli utenti gestiscono e interagiscono con i documenti. In questa guida, ti accompagneremo passo dopo passo nella creazione di un tuo plugin DocSpace, utilizzando esempi reali tratti dai nostri plugin ufficiali.

How to develop a DocSpace plugin – complete Step-by-Step Tutorial

Informazioni sull’SDK per plugin di ONLYOFFICE DocSpace

ONLYOFFICE DocSpace Plugins SDK è un pacchetto npm basato su motori TypeScript che fornisce interfacce che consentono di creare plugin personalizzati e integrarli nel portale DocSpace. Il ciclo di sviluppo del plugin comprende pianificazione, sviluppo, test e utilizzo.

Per illustrare come utilizzare il nostro Plugins SDK, abbiamo creato un repository con i plugin di esempio. Scopriamo insieme l’intero processo di sviluppo di un plugin a partire da questi esempi.

Pianificazione

Definisci lo scopo del plugin, pensa a dove verrà utilizzato e quali servizi di terze parti devono essere collegati.

Step 1. Installa tutti i pacchetti e i programmi necessari

Per installare il pacchetto npm @onlyoffice/docspace-plugin-sdk globalmente, utilizza il seguente comando:

 npm i -g @onlyoffice/docspace-plugin-sdk

Step 2. Progetta il funzionamento del tuo plugin

Scegli il servizio che consente di aggiungere la funzionalità necessaria al tuo DocSpace.

Ad esempio, nei nostri plugin di esempio utilizziamo:

  • AssemblyAI per convertire l’audio e il video in testo;
  • ConvertAPI per convertire documenti, fogli di calcolo, presentazioni e moduli in PDF;
  • Draw.io per creare, modificare e inserire diagrammi professionali.

Nota! Assicurati che la documentazione del servizio sia disponibile, verifica la licenza, la disponibilità dei metodi API, ecc. Alcuni servizi richiedono una chiave API per poter essere utilizzati.

Pensa a dove implementare il plugin, quale sarà la sua struttura, come l’utente interagirà con i suoi componenti, ecc. Compila un elenco dei tipi e degli elementi di plugin necessari in base a queste informazioni. Per maggiori dettagli, consulta le sezioni Tipi di plugin e Elementi di plugin della documentazione dell’SDK.

Ad esempio, per il plugin speech-to-text utilizziamo le seguenti interfacce:

  • IPlugin. Necessaria per ogni plugin. Contiene la variabile PluginStatus, utilizzata per integrare il plugin in DocSpace.
  • ApiPlugin. Necessaria per implementare un servizio di terze parti.
  • ISettingsPlugin e ISettings. Utilizzate per aggiungere un blocco di impostazioni per configurare il plugin. Gli utenti possono accedervi da Impostazioni -> Integrazione -> Plugin per modificare i parametri del plugin.
  • IContextMenuPlugin e IContextMenuItem. Utilizzate per implementare un’azione dal menù contestuale. Nel plugin speech-to-text sarà disponibile per file audio e video, permettendo di convertire il contenuto in testo.

L’elenco delle interfacce può essere più lungo. Ad esempio, nel plugin draw.io:

  • IMainButtonPlugin e IMainButtonItem. Utilizzate per implementare l’azione del pulsante principale. Nel plugin draw\.io vengono usati gli elementi Pulsante d’azione -> Altro nel menù della sezione I miei documenti o nella stanza selezionata per creare diagrammi draw\.io.
  • IFilePluginIFileItem. Utilizzate per interagire con i tipi di file specificati, in questo caso i file .drawio.

Progetta la struttura del plugin. Tutti i file richiesti sono descritti qui. Tutto il resto può essere organizzato come preferisci: ad esempio, nel plugin draw.io il codice per ogni tipo di plugin è collocato in cartelle separate, mentre nel plugin speech-to-text è tutto nel folder src.

(no title)
Scegli un nome per il tuo plugin e scrivi una descrizione.

Sviluppo

Ora che hai completato tutta la fase di preparazione, puoi iniziare a sviluppare il tuo plugin.

Step 1. Crea un template del plugin

Crea un template del plugin e configura le impostazioni che verranno visualizzate nelle impostazioni dei plugin in DocSpace:

Per creare un template del plugin, apri il terminale ed esegui il seguente comando npx:

 npx create-docspace-plugin

Se il comando npx non è disponibile, installa il pacchetto npm @onlyoffice/docspace-plugin-sdk globalmente utilizzando il seguente comando:

npm i -g @onlyoffice/docspace-plugin-sdk

Configura il plugin nel terminale specificando le impostazioni nella finestra di dialogo. Tutte le impostazioni sono descritte qui.

Per il plugin speech-to-text puoi usare i seguenti valori:

(no title)
Puoi modificare tutti i parametri specificati successivamente nel file package.json.

Puoi anche creare un plugin in qualsiasi progetto aggiungendo il pacchetto npm @onlyoffice/docspace-plugin-sdk come dipendenza e specificando tutti i campi necessari nel file package.json.

Passaggio 2. Configura il punto di ingresso del plugin

Il punto di ingresso del plugin index.ts verrà creato automaticamente nella cartella src durante la fase di creazione del template. Questo file è obbligatorio.

Il file contiene tutti i metodi di base dei tipi di plugin che hai selezionato nel passaggio precedente. Puoi modificare questo file in qualsiasi momento.

Se crei un plugin manualmente senza usare un template, puoi utilizzare il codice dai nostri plugin di esempio già pronti come punto di partenza: funzionerà perfettamente.

Passaggio 3. Aggiungi le icone del plugin

Crea la cartella assets nella directory principale del plugin e aggiungi tutte le icone del plugin. Il numero di icone e le loro dimensioni dipendono dai tipi di plugin implementati. Per il plugin speech-to-text sono necessarie le seguenti icone:

  • Il tipo di plugin predefinito richiede un’immagine logo. Questa corrisponde al parametro logo del file package.json e viene visualizzata nelle impostazioni del plugin in DocSpace. La dimensione richiesta è 48×48 px. In caso contrario, sarà ridimensionata a questa misura.(no title)
  • Il plugin di tipo menù contestuale utilizza un’icona sul pulsante Converti in testo. La dimensione richiesta è 16×16 px. Altrimenti sarà ridimensionata.

(no title)
Questa icona può essere utilizzata anche per il pulsante principale. Ad esempio, nel plugin draw.io, la stessa icona è usata sia per il menù contestuale che per il pulsante principale.

(no title)
Il plugin draw\.io utilizza inoltre un’icona file specifica accanto ai file .drawio, creata con il tipo di plugin file. La dimensione consigliata per la visualizzazione in formato tabella è 32×32 px.

(no title)

Passaggio 4. Configura gli elementi dell’interfaccia del plugin

Ad esempio, il plugin draw\.io contiene due elementi principali dell’interfaccia utente: la finestra modale e l’editor dei diagrammi. Crea i file per configurare ciascun elemento. Per comodità, puoi inserire questi file in una cartella separata denominata DrawIO.

Nel file Dialog.ts, configura le impostazioni della finestra modale. Specifica il componente UI IFrame utilizzato per incorporare il sito web di draw.io all’interno della finestra modale:

  export const frameProps: IFrame = {
    width: "100%",
    height: "100%",
    name: "test-drawio",
    src: "",
  }

Crea il container IBox per aggiungervi l’iframe:

 const body: IBox = {
    widthProp: "100%",
    heightProp: "100%",


    children: [
      {
        component: Components.iFrame,
        props: frameProps,
      },
    ],
  }

Configura le proprietà della finestra 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,

Nel file Editor.ts, configura l’editor di diagrammi. Crea la funzione DiagramEditor con i seguenti parametri:

Parametro Tipo Esempio Descrizione
ui string “default” Definisce il tema UI dell’editor.
dark string “auto” Definisce il tema scuro dell’editor.
off boolean false Specifica se la modalità offline è attiva o meno.
lib boolean false Specifica se le librerie sono abilitate o meno.
lang string “auto” Definisce la lingua dell’editor.
url string `https://embed.diagrams.net` Definisce l’URL dell’editor.
showSaveButton boolean true Specifica se il pulsante **Salva** sarà visibile nell’editor.

Quindi specifica i metodi per lavorare con i diagrammi:

Metodo Descrizione
startEditing Avvia l’editor con i dati forniti.
getData Restituisce i dati del diagramma.
getTitle Restituisce il titolo del diagramma.
getFormat Restituisce il formato del diagramma.
getFrameId Restituisce l’ID del frame dell’editor.
getFrameUrl Restituisce l’URL dell’iframe.
handleMessage Gestisce il messaggio fornito.
initializeEditor Invia il messaggio *load* all’editor.
save Salva i dati forniti.

Il codice completo di DiagramEditor è disponibile qui.

Passaggio 5. Crea i tipi di plugin

Ora che il plugin predefinito è pronto, puoi iniziare a scrivere altri tipi di plugin.

Ogni tipo di plugin ha voci specifiche. Definisci la voce del menù contestuale che verrà visualizzata facendo clic con il tasto destro su file audio o video:

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,
}

(no title)
Puoi aggiungere altri tipi di plugin. Ad esempio, il plugin draw.io può essere accessibile dal menù principale, quindi è necessario specificare la voce del pulsante principale:

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],
}

Quando si fa clic sulla voce del pulsante principale, viene visualizzata una finestra modale dove è possibile digitare il nome del diagramma e aprire un file .drawio vuoto.

(no title)
Per il plugin draw.io, è necessario anche configurare il tipo di file plugin, che viene utilizzato quando l’utente apre un file con estensione .drawio:

Definisci la voce di file rappresentata da un file con estensione specifica (.drawio) e icona:

 export const drawIoItem: IFileItem = {
     extension: ".drawio",
     fileTypeName: "Diagram",
     fileRowIcon: "drawio-32.svg",
     fileTileIcon: "drawio-32.svg",
     devices: [Devices.desktop],
     onClick,
   }

Definisci l’evento onClick che eseguirà il metodo editDiagram ogni volta che viene aperto un file .drawio:

  const onClick = async (item: File) => {
     return await drawIo.editDiagram(item.id)
   }

(no title)

Passaggio 6. Crea il tipo di plugin delle impostazioni

Configura il tipo di plugin delle impostazioni per fornire all’utente le opzioni amministrative.

Crea un contenitore in cui verranno posizionate le impostazioni del plugin:

 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],
   }

Nella descrizione delle impostazioni, indica che è necessario generare un token API per poter utilizzare il plugin.

Configura le impostazioni amministrative con l’oggetto 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}
     }

Specifica l’evento onLoad, che definisce quali impostazioni del plugin saranno visualizzate quando il blocco impostazioni viene caricato.

Ogni elemento delle impostazioni è definito in file separati (buttons, token).

(no title)

Passaggio 7. Crea il file principale del plugin

Crea un file nella cartella src contenente il codice principale del plugin. Questo file è obbligatorio. Consulta la documentazione del servizio di terze parti per scrivere questo codice.

Vediamo in dettaglio com’è organizzato il file AssemblyAI.ts:

Definisci la classe AssemblyAI con tutte le variabili e i metodi necessari:

  • Variabili e loro descrizione:

apiURL

Definisce l’URL dell’API.

apiURL = ""

currentFileId

Definisce l’ID del file corrente.

const currentFileId: numbernull | number = null

apiToken

Definisce il token API.

 apiToken = ""
  • Metodi e le loro applicazioni

createAPIUrl

Crea l’URL dell’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

Imposta l’URL dell’API.

 setAPIUrl = (url: string) => {
     this.apiURL = url
   }

getAPIUrl

Restituisce l’URL dell’API.

 getAPIUrl = () => {
     return this.apiURL
   }

setAPIToken

Imposta il token dell’API.

   setAPIToken = (apiToken: string) => {
     this.apiToken = apiToken
   }

getAPIToken

Restituisce il token dell’API.

   getAPIToken = () => {
     return this.apiToken
   }

fetchAPIToken

Recupera il token dell’API.

   fetchAPIToken = async () => {
     const apiToken = localStorage.getItem("speech-to-text-api-token")
  
     if (!apiToken) {
       return
     }


     this.setAPIToken(apiToken)
     plugin.updateStatus(PluginStatus.active)
   }

saveAPIToken

Salva il token dell’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

Imposta l’ID del file corrente.

 setCurrentFileId = (id: number | null) => {
     this.currentFileId = id
   }

uploadFile

Carica un file che verrà trascritto.

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

Trascrive il file 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

Implementa la funzionalità del 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
   }

Dichiara l’istanza della classe AssemblyAI:

const assemblyAI = new AssemblyAI()

Esporta l’istanza del plugin creata:

export default assemblyAI

Test

Per verificare il funzionamento del plugin e correggere eventuali bug, testa il plugin:

  • Compila il plugin preparato seguendo le istruzioni qui

La cartella dist verrà creata nella directory principale del plugin e l’archivio del plugin sarà collocato al suo interno. Questo archivio rappresenta il plugin completo che può essere caricato sul portale DocSpace.

  • Carica il tuo plugin nel portale DocSpace e testane attentamente aspetto e funzionalità.

Nota! Tieni presente che puoi caricare i tuoi plugin solo nella versione server di DocSpace.

Se si verificano bug, correggi il codice sorgente del plugin e ripeti la procedura di compilazione e test.

Ora che il tuo plugin è stato testato e funziona correttamente, puoi aggiungerlo alla versione server di DocSpace e iniziare a usarlo.

Il plugin DocSpace offre un approccio potente e intuitivo alla gestione documentale e alla collaborazione. Integrandosi con le piattaforme preferite dagli utenti, elimina gli ostacoli più comuni e migliora la produttività nei diversi flussi di lavoro. Se hai domande sui plugin DocSpace, non esitare a contattare i nostri sviluppatori sul forum di ONLYOFFICE (è richiesta la registrazione).
Puoi anche richiedere una funzione o segnalare un bug aprendo un ticket su GitHub oppure condividere i tuoi plugin DocSpace con noi e con altri utenti. Buona fortuna con i tuoi progetti di sviluppo!

Crea il tuo account ONLYOFFICE gratuito

Visualizza, modifica e collabora su documenti, fogli, diapositive, moduli e file PDF online.