Comment nous avons créé la prise en charge des widgets pour les applications dans MyStore

Bonjour à tous! MySklad Marketplace est à l'antenne. La dernière fois, nous avons parlé de la façon dont nous avons lancé des applications marketpleys dans le service SaaS MoySklad . Aujourd'hui, nous allons continuer sur la façon dont nous permettons aux applications d'étendre l'interface utilisateur du service. Probablement, beaucoup se sont rencontrés dans des applications de bureau avec des plugins similaires, qui, lorsqu'ils sont connectés, ajoutent certains de leurs propres boutons, éléments de menu et même des ensembles entiers de nouvelles fenêtres et boîtes de dialogue à l'application, et intègrent également leurs propres blocs d'interface utilisateur dans les écrans existants. . Comment faire cela dans un service SaaS doté d'une interface utilisateur de navigateur?





Pourquoi intégrer l'interface utilisateur?

Au début de la Marketplace pour les applications à usage général, le seul moyen disponible pour intégrer des applications avec MyStore est l'intégration de données via une API JSON commune . Grâce à cette API, le backend des applications des fournisseurs peut recevoir et modifier les données utilisateur. Ainsi, au départ, nous n'avions que la possibilité d'intégrer les backends applicatifs et MyStore les uns avec les autres. Ils n'ont pas pu ajouter un bouton ou un widget au formulaire de modification de l'application.





Au départ, il était évident que cela ne suffisait pas pour offrir aux utilisateurs finaux la meilleure expérience applicative possible. D'autre part, les développeurs et intégrateurs externes devaient regrouper leurs mécanismes dans l'interface utilisateur - ils avaient le choix soit de s'intégrer directement dans les applications Web HTML de MyStore via des plugins de navigateur, soit de créer des interfaces séparées (UI) de leur côté, en grande partie. duplication de la fonctionnalité des écrans dans MyStore (par exemple, listes de documents avec filtres).





, — , ( ). — , , . , () , .





, , UI- — must have , .





— — iframe . , , . . 





UI- -.





.

, , SaaS-.





. UI, .





:





:













  1. ,









:





  • . . , , ( ) UI ( ) (UX).





  • . . , , , “” .





  • / . , UI — SPA, : DOM- , UI — . , .





?

SaaS- (Jira, Salesforce, Zendesk) (amoCRM, 24, InSales). .





:





  1. : SPA - ?





  2. - (- , iframe ), , SDK ( UI)?





  3. , ?





  4. . , / .





. , .





, SPA- “” SPA (“” — , , UI SPA, - — ). UI — SPA. 





iframe’. :





  1. iframe , ( , — ). sandbox iframe’a allow-same-origin



    , DOM - . - , , JavaScript-. ().





  2. iframe ( allow-same-origin



    ) — , DOM- - . . - postMessage, , , , JavaScript- - . , postMessage JS SDK — JavaScript-.





JS SDK. JS SDK API , API “” postMessage JavaScript-.





amoCRM, DOM- -. , , , — , UI. , . , , , - .





(, ) — JSON- (). XML — XML- ( JSON-). XML JSON’a — .





XML-

, , :





<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"             
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"             
                    xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2      
                    https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
    <iframe>
        <sourceUrl>https://example.com/iframe.html</sourceUrl>
        <expand>true</expand>
    </iframe>
    <vendorApi>
        <endpointBase>https://example.com/dummy-app</endpointBase>
    </vendorApi>
    <access>
        <resource>https://online.moysklad.ru/api/remap/1.2</resource>
        <scope>admin</scope>
    </access>
    <widgets>        
        <entity.counterparty.edit>            
            <sourceUrl>https://example.com/widget.php</sourceUrl>            
            <height>                
                <fixed>150px</fixed>            
            </height>
            <supports>
                <open-feedback/>
                <save-handler/>
            </supports>
            <uses>
                <good-folder-selector/>
            </uses>                  
        </entity.counterparty.edit>    
    </widgets>
    <popups>
        <popup>
            <name>somePopup</name>
            <sourceUrl>https://example.com/popup.php</sourceUrl>
        </popup>
        <popup>
            <name>somePopup2</name>
            <sourceUrl>https://example.com/popup-2.php</sourceUrl>
        </popup>
    </popups>
</ServerApplication>

      
      



, XML, JSON? , XML — XML Schema. JSON — , JSON Schema. JSON- ( XML-) , , IDE. , JSON- . , XML- . JSON-, , XML JSON , XML- .





? :





  1. , . , , , - . — .





  2. code completion IDE “ ” UI . - ( ), .





, , Intellij IDEA , :





IDE open-feedback ( - ):





:





.





XML-

( ) . , ( ) . — . , . , . . . .   





. , . , — , , , , , , - . , , - , . .





, XML-:





<widgets>
    <some.extension.point1>...</some.extension.point1>
    <some.extension.point2>...</some.extension.point2>
</widgets>
      
      



, , :





<widgets>
    <widget location="some.extension.point1">...</widget>
    <widget location="some.extension.point2">...</widget>
</widgets>
      
      



XML- (“”) . - “” — . , XML-, XML-.





? , , ?





:





<document.customerorder.edit>
    <sourceUrl>https://example.com/widget.php</sourceUrl>
    <height>
        <fixed>150px</fixed>
    </height>
    <supports>...</supports>
    <uses>...</uses>
</document.customerorder.edit>
      
      



sourceUrl



height



. sourceUrl



iframe, height



( , — , , UI).





( ) - (, , ), , <height><dynamic/></height>



. — . , , <dynamic/>



, . 





supports



uses



. .





( API , ):





:





<document.customerorder.edit>
    <sourceUrl>https://example.com/widget.php</sourceUrl>
    <height>
        <fixed>150px</fixed>
    </height>
    <supports>
        <open-feedback/>
        <save-handler/>
        <change-handler>
            <expand>agent</expand>
            <expand>positions.assortment</expand>
        </change-handler>
    </supports>
    <uses>
        <good-folder-selector/>
    </uses>
</document.customerorder.edit>
      
      



.





— , UI , . , HTTP postMesssage. .





.





— , / ( ). . , sourceUrl



height



, iframe HTTP - postMessage- Open



.





DOM- :





Open



:





{
  "name": "Open",
  "messageId": 12345,
  "extensionPoint": "entity.counterparty.edit",
  "objectId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c",
  "displayMode": "expanded"
}
      
      



— ( ) , . supports



( ). .





supports



. .





pen-feedback



( ) — , , , OpenFeedback



. , . - , .





:





OpenFeedback



:





{
  "name": "OpenFeedback",
  "correlationId": 12345
}  
      
      



save-handler



( ) — , - “” Save



.





Save



:





{
  "name": "Save",
  "messageId": 32109,
  "extensionPoint": "entity.counterparty.edit",
  "objectId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c"
}
      
      



hange-handler



( ) — , , , ( ). , change-handler



, - “” — - (, ) - Change



JSON . expand



, JSON API ( change-handler



expand



).





— , - . . uses ( ). , -> - -.





— good-folder-selector



. . :





1. - SelectGoodFolderRequest



(, - ):





{
  "name": "SelectGoodFolderRequest",
  "messageId": 12345
}
      
      



2. - :





3. - SelectGoodFolderResponse



:





{
  "name": "SelectGoodFolderResponse",
  "correlationId": 12345,
  "selected": true,
  "goodFolderId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c"
}
      
      



:





  1. , .





  2. XML- , ( ). 





  3. / , . : , , - , , , .





  4. , -. , change-handler, - , ( SPA- ).





(, - Init postMessage, iframe. , , ( ), (, ). , , — , - , ( ). , .





. .





?

?





. - , . - . . iframe, . postMessage- -. .





change-handler



. — update



, -.





:





  • “” postMessage JavaScript/TypeScript Widget SDK









  • UI- ( ) — , :





    • ,

























  • UI





  • RESP API Widget SDK





UI — SaaS- , .





— email- , , .





SaaS- — — , .








All Articles