Sovellusten (liitännäisten) kirjoittaminen

Sovellukset lisäävät Antimatteriin toiminnallisuutta sisältä: Go-kielinen palvelinosa, joka kytketään palvelimeen, ja React-kielinen web-sovellusosa, joka lisää valikot, paneelit, viestityypit ja sivut. Tässä sivussa näytetään sovelluksen rakenne käyttäen mukana toimitettavaa Kyselyt-sovellusta esimerkkinä, ja mitä muutoksia Antimatterin Fusion-käyttöliittymässä tapahtuu.

Sovelluksen toimintaperiaate

  • Palvelinosa on Go-ohjelma. Palvelin käynnistää sen erillisenä prosessina ja kommunikoi sen kanssa RPC:n kautta: se kutsuu sovelluksen koukuja (viesti on postitumassa, komento suoritettiin…) ja sovellus kutsuu palvelimen liitännäis-API:ta (luo viesti, lue käyttäjä, tallenna dataa…). Se voi myös palvella HTTP-reittejä polulla /plugins/<app id>/.
  • Web-sovellusosa on JavaScript-paketti, joka ladataan selaimeen web-sovelluksen mukana. Se rekisteröi React-komponentit ja takaisinkutsut rekisteriin: valikon painike, paneeli, tapa piirtää viestityyppi.
  • Molemmat osat ovat valinnaisia. Sovellus asennetaan .tar.gz-pakkina, ja järjestelmän ylläpitäjät voivat ottaa sen käyttöön, poistaa sen käytöstä ja määrittää sen asetukset.
Palvelinosa ajetaan täydellä pääsyoikeudella palvelimen dataan. Kohtele sovellusta kuten koodia, jonka deployaat palvelimelle.

Antimatter ajaa Mattermostille kirjoitettuja sovelluksia ja toisinpäin, niin kauan kuin sovellus käyttää vain koukuja, joita molemmilla on. Katso Vain Antimatterin omaat koukut.

Paketin rakenne

Ei ole erillistä aloituspohjaa: aloita pienestä mukana toimitetusta sovelluksesta, kuten antimatter-plugin-polls tai antimatter-plugin-todo, ja muuta sen ID:tä ja koodia. Kyselyt-sovellus on rakennettu tällä tavalla:

antimatter-plugin-polls/
├── plugin.json            the manifest
├── Makefile               build, test, bundle, deploy
├── build/                 the manifest and pluginctl helper tools (Go), setup.mk
├── assets/icon.svg        files shipped with the bundle
├── go.mod
├── server/
│   ├── main.go            plugin.ClientMain(&Plugin{})
│   ├── plugin.go          the Plugin type, OnActivate, ServeHTTP
│   ├── manifest.go        generated from plugin.json
│   ├── api.go, command.go, hooks.go, store.go …
│   └── dist/              compiled binaries, one per platform
└── webapp/
    ├── package.json, webpack.config.js, tsconfig.json
    ├── i18n/              en.json and one file per language
    ├── src/index.tsx      registers the app with the web app
    ├── src/manifest.ts    generated from plugin.json
    ├── src/translations.ts
    └── dist/main.js       the bundle

Valinnainen: public/-kansio, joka palvelletaan sellaisenaan polulla /plugins/<app id>/public/.

plugin.json

{
  "id": "com.example.weather",
  "name": "Weather",
  "description": "Forecasts in the chat.",
  "homepage_url": "https://github.com/example/weather",
  "support_url": "https://github.com/example/weather/issues",
  "icon_path": "assets/icon.svg",
  "version": "1.0.0",
  "min_server_version": "12.0.0",
  "server": {
    "executables": {
      "linux-amd64": "server/dist/plugin-linux-amd64",
      "linux-arm64": "server/dist/plugin-linux-arm64",
      "darwin-amd64": "server/dist/plugin-darwin-amd64",
      "darwin-arm64": "server/dist/plugin-darwin-arm64",
      "windows-amd64": "server/dist/plugin-windows-amd64.exe"
    }
  },
  "webapp": {"bundle_path": "webapp/dist/main.js"},
  "settings_schema": {"settings": []}
}
  • id: ainutlaatuinen ja pysyvä; käänteinen verkkotunnus on yleistä. Se nimetää reitit, tallennetut asetukset ja WebSocket-tapahtumat.
  • version: semanttinen versio. Mukana toimitetut sovellukset jättävät sen pois plugin.json-tiedostosta; niiden rakennustyökalu hakee sen uusimmasta v*-git-tagista.
  • min_server_version: Antimatter raportoi 12.0.0.
  • settings_schema: sovelluksen asetussivu Järjestelmäkonsolissa (ks. Asetukset).

make apply kopioi manifestin tiedostoihin server/manifest.go ja webapp/src/manifest.ts; make manifest-check validoi sen.

Palvelinosa

Palvelinosa tuottaa saman Go-moduulin kuin Mattermost-sovellukset, github.com/mattermost/mattermost/server/public, Go-moduuliproksista. Sen main käynnistää vain sovelluksen:

package main

import "github.com/mattermost/mattermost/server/public/plugin"

func main() {
	plugin.ClientMain(&Plugin{})
}

Plugin-tyyppi upottaa plugin.MattermostPlugin-tyypin, joka antaa sille p.API:n, ja toteuttaa tarvitsemansa hookit:

type Plugin struct {
	plugin.MattermostPlugin
	router *mux.Router
}

func (p *Plugin) OnActivate() error {
	p.router = p.newRouter()
	return p.API.RegisterCommand(&model.Command{
		Trigger:          "weather",
		AutoComplete:     true,
		AutoCompleteDesc: "Show the forecast",
		AutoCompleteHint: "[city]",
	})
}

func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
	city := strings.TrimSpace(strings.TrimPrefix(args.Command, "/weather"))
	return &model.CommandResponse{
		ResponseType: model.CommandResponseTypeEphemeral,
		Text:         "Forecast for " + city + ": sunny",
	}, nil
}

func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
	p.router.ServeHTTP(w, r)
}

Yleiset hookit

HookKun se ajetaan
OnActivate, OnDeactivateKun sovellus otetaan käyttöön tai poistetaan käytöstä, sekä kun palvelin käynnistyy ja pysähtyy. Rekisteröi komennot ja botit OnActivate-hookissa.
OnConfigurationChangeKun sen asetukset muuttuvat; lue ne komennolla p.API.LoadPluginConfiguration(&cfg).
ServeHTTPPyyntö osoitteeseen /plugins/<app id>/…. Palvelin asettaa Mattermost-User-Id-otsikon, kun pyyntö tulee kirjautuneelta käyttäjältä; hylkää pyynnöt, joissa ei tätä ole, ellei ne ole tarkoitettu julkisiksi.
ExecuteCommandSovelluksen rekisteröimä komento suoritettiin.
MessageWillBePosted, MessageWillBeUpdatedEnnen viestin tallentamista: palauta muuttunut viesti tai syy hylkäyselle.
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeletedTapahtuman jälkeen, sivuvaikutuksia varten.
ReactionHasBeenAdded, ReactionHasBeenRemovedReaktiot.
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreatedJäsenyyden ja kanavien muutokset. Tiimi on yhteisö.
FileWillBeUploadedEnnen tiedoston tallentamista: muuta tai hylkää se.
OnPluginClusterEventViesti samasta sovelluksesta toisesta klusterin palvelimesta.

Täydellinen luettelo, täydellisillä allekirjoituksilla, on tiedostossa server/public/plugin/hooks.go; API on tiedostossa server/public/plugin/api.go. pluginapi-paketti (server/public/pluginapi) kääsee API:n ystävällisemmiksi apurutiineiksi.

Hyödylliset API-kutsut

  • CreatePost, UpdatePost, SendEphemeralPost: julkaise sovelluksen bottina tai käyttäjänä.
  • EnsureBotUser(&model.Bot{Username, DisplayName}): luo sovelluksen botti kerran ja hae sen ID.
  • PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): lähetä tapahtuma web-sovellukselle. Se saapuu nimellä custom_<app id>_poll_updated.
  • OpenInteractiveDialog: avaa dialogi.
  • LogInfo, LogError ja vastaavat: kirjoita palvelinlokiin, merkitty sovelluksen ID:llä.
  • GetUser, GetChannel, HasPermissionToChannel: tarkista, kuka saa tehdä mitä, ennen kuin toimit käyttäjän puolesta.

Sovellus ajetaan jokaisella klusterin palvelimella. Säilytä tila avain-arvo-tallennuksessa tai tietokannassa, ei vain muistissa.

Tekoälypalvelu

Antimatterin palvelu kutsuu sovellusten puolesta tekoälymalleja, käyttäen ylläpitäjän määrittämiä malliyhteyksiä (ks. Tekoäly ylläpitäjän opasteessa). Sovellus ei koskaan säilytä palveluntarjoajan avainta: se ilmoittaa, kenen puolella ja missä se toimii, ja palvelu tarkistaa, että kyseisellä henkilöllä on oikeus käyttää yhteyttä siinä paikassa, soveltaa sen rajoituksia ja budjetteja, laskee tokenit henkilön ja sovelluksen laskuun ja tekee tilauskirjauksen kutsusta sisältöä sisällyttämättä.

MetodiToiminto
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest)Chat-täydennys: viestit, työkalut, strukturoitu tulos (JSONSchema).
AIChatStream(…)Sama, virtana: lue virtan Events-tapahtumat, kunnes kanava suljetaan, tai Close-metodilla lopeta kutsu.
AIEmbed(…, *ai.EmbedRequest)Tekstien upotukset (embeddings).
AITranscribe(…, *ai.TranscribeRequest)Puhe tekstiksi.
AIDecide(…, *ai.DecideRequest)Tyypillistettyjä kysymyksiä päätösmallille (kyllä tai ei, valinta, pistemäärä) tekstistä.
AIConnectionsForUser(userID, channelID, teamID)Yhteydet, joita henkilö voi siellä käyttää, niiden malleineen ja ominaisuuksineen, mutta ei koskaan avaimineen.

Jokaisen pyynnön ConnectionID valitsee yhteyden, ja Model sen mallin (tyhjä arvo käyttää yhteyksen oletusmallia). Operation on lyhyt tunniste käytön ja tilauskirjanpidon merkintöjä varten, ei sisältöä. Niiden vähimmäispalvelinversio on 11.11.

Ota actingUserID vain lähteestä, jonka palvelu on varmistanut: Mattermost-User-Id-otsake pyynnössä ServeHTTP-pisteeseesi, tai hakukoodin kontekstin käyttäjä (viestin kirjoittaja, komennon suorittanut käyttäjä). Älä koskaan ota sitä viestistä, webhook-pakettista, URL:stä tai toisen sovelluksen pyynnöstä: sovelluksesi käyttäisi muun henkilön pääsyä.

Nämä metodit ja ai-paketti (server/public/ai) ovat olemassa vain Antimatterin kopiossa moduulista, eivät Mattermostin julkaisemassa versiossa. Käyttääksesi niitä, käännä koodi Antimatterin server/public-pakettia vasten käyttäen replace-riviä go.mod-tiedostossasi, esimerkiksi replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public. Tällainen sovellus toimii vain Antimatterissa.

Työkalujen tarjoaminen agenteille

Sovellus tarjoaa omat työkalunsa agenteille käyttämällä funktiota RegisterAITools([]*model.AIToolDefinition): määritä jokaiselle työkalulle nimi, otsikko, kuvaus, syötteen JSON-kaavio ja tyyppi (read, write tai external_write). Tyyppi määrää, voiko agentin käytäntö suorittaa työkalun itsenäisesti (katso Työkalut ylläpito-oppaasta). Oikeudet tarkistetaan kutsun kanava- tai yhteisöargumentista tai palvelimella työkalun tarpeiden mukaan. Kun agentti käyttää työkalua, palvelin kutsuu ExecuteAITool(c, *model.AIToolExecution) *model.AIToolResult-koukkua, ja pyynnön tehnyt henkilö on määritetty UserId-kentässä. Toimi vain tämän henkilön oikeuksilla, ei koskaan agentin oikeuksilla. Työkalut nimetään muodossa <app id>.<name>. Vähimmäispalvelinversio on 11.11. Nämä metodit ja koukku ovat olemassa vain Antimatterin server/public-kirjastossa, kuten edellä mainittu AI-palvelu. Sovellus, jonka ID on antimatter tai joka alkaa merkkijonolla mcp., ei voi rekisteröidä työkaluja.

Tietojen tallentaminen

Jokaisella sovelluksella on oma avain-arvo-tallennus palvelimen tietokannassa:

  • KVSet(key, value), KVGet(key), KVDelete(key): arvot ovat tavuja, tyypillisesti JSON-muodossa. Avaimet ovat enintään 150 merkkiä.
  • KVSetWithExpiry(key, value, seconds): arvo poistuu tämän ajan jälkeen.
  • KVCompareAndSet(key, old, new) ja KVSetWithOptions -parametrilla Atomic: turvalliset päivitykset, kun useat pyynnöt tai palvelimet kirjoittavat samaa avainta. Polls-tiedote tallentaa jokaisen äänen tällä tavalla ja yrittää uudelleen konfliktin tapauksessa.
  • KVList(page, perPage): avaimet sivulta toiselle.

Web-sovelluksen osa

Paketti rekisteröi luokan metodilla window.registerPlugin. Sen initialize-metodi saa rekisterin ja Redux-tallennuksen:

import manifest from './manifest';

class Plugin {
    initialize(registry, store) {
        registry.registerTranslations((locale) => translationsFor(locale));
        registry.registerPostTypeComponent('custom_poll', PollPost);
        registry.registerWebSocketEventHandler(`custom_${manifest.id}_poll_updated`, (msg) => {
            store.dispatch(pollUpdated(JSON.parse(msg.data.poll)));
        });
        registry.registerReconnectHandler(() => store.dispatch(reloadPolls()));
    }
}

window.registerPlugin(manifest.id, new Plugin());
  • Yhteiset kirjastot. Web-sovellus tarjoaa Reactin, ReactDOM, Redux, React Reduxin ja React Intl:in: listaa ne webpackin externals-osassa (React, ReactDOM, Redux, ReactRedux, ReactIntl) sen sijaan, että pakettaisit omat kopiosi. Katso Polls-tiedotteen webpack.config.js.
  • Palvelinosan kutsuminen. Hae osoitteesta ${window.basename}/plugins/<app id>/… vaihtoehdot, jotka saat metodista Client4.getOptions() (moduulista mattermost-redux/client): ne sisältävät otsakkeet, joita palvelin tarvitsee hyväksyäkseen pyynnön selaimesta.
  • Oma tilasi. registerReducer lisää reducerin, joka tallennetaan osoitteeseen state['plugins-<app id>'].
  • Tyyppitiedot. Antimatterin lisärekisterimetodit eivät sisälly Mattermostin julkaisemiin tyyppitietoihin: Polls-tiedote määrittelee käyttämänsä rekisterin tiedostossa webapp/src/types/host.ts.

Rekisterin metodit ja niiden parametrit on dokumentoitu koodissa, tiedostoissa webapp/fusion/src/plugins/registry.ts (Fusion) ja webapp/channels/src/plugins/registry.ts (klassinen).

Fusion-käyttöliittymän tuki

Antimatterilla on kaksi web-käyttöliittymää: Fusion, joka on oletus, ja klassinen. Molemmat lataavat samat sovelluspaketit ja käyttävät samaa rekisteriä, mutta Fusion piirtää monia asioita itse ja sijoittaa lisäosien komponentit omalla tavallaan. Testaa sovelluksesi molemmissa.

Käyttöliittymän tunnistaminen

Ennen kuin mikään sovellus latautuu, molemmat käyttöliittymät asettavat window.antimatterWebUI-muuttujan arvoksi 'fusion' tai 'classic', ja saman arvon sivun juurelementtiin ominaisuutena data-am-web-ui. Mattermostissa kumpikaan ei ole asetettu.

export function isFusionUI(): boolean {
    return window.antimatterWebUI === 'fusion' || document.documentElement.dataset.amWebUi === 'fusion';
}

Sisällytetyt sovellukset käyttävät tätä piirtääkseen käyttöliittymän eri tavalla. Kyselyt piirtävät kyselykortit Fusionin tyyliin, ja Fusionissa kysely kirjoitetaan viestiruutuun (viestiruudun tila) dialogin sijaan. Puhelut ja äänikanavat jättävät pois sivupalkin ja ilmoituskomponentit, jotka Fusion korvaa omalla puheluikkimallaan. Tekoälykeskustelusovellus laittaa tekoälytoimintonsa viestivalikkoon Lisätoiminnot-ryhmän alle hover-työkalurivin sijaan. Nämä sovellukset käyttävät Fusionin omia CSS-luokkia (etuliite am-) ja dialogikerrosta (am-layer-elementti) sovittaakseen käyttöliittymän; nämä eivät ole dokumentoitu, vakaa API.

Missä Fusion näyttää lisäosakomponentit

RekisteröintimenetelmäMissä se näkyy Fusionissa
registerAppBarComponent, registerChannelHeaderButtonActionSovelluspalkki, ikoneiden sarake oikealla reunassa, avatarin ja Tietoja Antimatterista-painikkeen välissä. Kanavan otsikon painikkeet sijoitetaan sinne, eivät kanavan otsikkoon. Piilossa, jos järjestelmän ylläpitäjä ottaa Poista Apps Bar -palkki käytöstä (ExperimentalSettings.DisableAppBar, oletus poissa) käyttöön.
registerRightHandSidebarComponentOikeanpuoleinen paneeli. Sen otsikkopalkki on Fusionin, ja se on sama kaikille sovelluksille: sovelluksen kuvake ja nimi (rekisteröity otsikko, jos piirretään vain tekstiä, muuten sovelluspalkin etiketti tai manifestin nimi), sitten Palauta paneelin koko (kun kokoa on muutettu), Avaa uuteen ikkunaan ja Sulje. Otsikko, joka piirtää muuta (ohjaimen, linkin tai kuvan), jätetään pois, joten piirrä sovelluksesi omat ohjaimet paneeliin itse, esimerkiksi kapealle riville sen yläosaan. Käyttäjät voivat muuttaa paneelin kokoa vetämällä sen reunasta. Katso Paneeli uudessa ikkunassa.
registerChannelHeaderIconKanavan otsikon ikonit, puhelinpainikkeiden jälkeen; puhelimissa otsikon Lisää -valikossa.
registerCallButtonActionKanavan otsikon puhelupainike; useat palveluntarjoajat jakavat Muita tapoja soittaa-valikon.
registerPostDropdownMenuActionViestin Viestitoiminnot (⋯) -valikko, sen Lisätoiminnot-ala-valikossa; myös ketjupaneelin Ketjun toiminnot-valikossa, Lisätoiminnot-kohdan alla. Fusion piirtää sovelluksen ikoon ennen jokaista toimintoa, harmaana: sisällytetyille sovelluksille sen oman ikoon, muuten sovelluksen ikoon sovelluspalkissa, muuten neutraalin. Elementti ilman tekstiä toiminnon tekstin alussa (ikoni, jonka sovellus piirtää itse) on piilossa.
registerPostDropdownSubMenuActionRyhmä kohteita samassa Lisätoiminnot-alivalikossa yksittäisten toimintojen jälkeen, erotettuna viivalla ilman otsikkoa. Yksikään sovellus ei saa omaa kohtaa viestivalikkoon.
registerPostActionComponentViestin hover-työkalupalkki, ⋯-painikkeen edessä.
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponentViesti itse: sen runko, tekstin alla, ajan jälkeen ja linkkien esikatselujen tilalla.
registerChannelHeaderMenuActionKanavan Kanavan vaihtoehdot-valikko (⋯ sivupalkin kanavassa tai oikea napsautus), kohtina joissa on pistooli-ikoni.
registerMainMenuActionYhteisön valikko (yhteisön nimi kanavalistan yläreunassa), Lisätoiminnot-kohdan alla, ryhmiteltynä sovellusten mukaan.
registerSidebarBrowseOrAddChannelMenuActionYhteisön valikko, Luo kanava - ja Luo kategoria -kohtien jälkeen.
registerFileUploadMethodKirjoitusruudun + -valikko (Lisää viestiin), Lähetä tiedosto -kohdan jälkeen.
registerPostEditorActionComponentKirjoitusruudun muotoilupalkki, kun muotoilua näytetään.
registerAIActionMenuItemComponentKirjoitusruudun AI -valikko.
registerFileDropdownMenuAction, registerFilePreviewComponentTiedoston valikkomenu ja tiedoston esikatselu.
registerUserSettingsProfiili & asetukset, yksi välilehti per sovellus Liiteohjelmat-otsikon alla.
registerChannelSettingsTabKanavan asetukset -dialogi, Sovellukset -otsikon alla.
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponentProfiilikortti, joka näkyy, kun napsautat nimeä tai profiilikuvaa.
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponentYhteisön kanavalistan yläreuna, kanavan nimen ja ikoon viereen sekä yhteisön vasemmanpuoleisen sivupalkin alareuna.
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholderKanavan historian alku, viestilistan yläreuna, lukemattomien viestien raja, kirjoituskentän yläpuolella ja kirjoituskentän placeholder-teksti.
registerChannelTypeOptionLuo kanava-dialogin kanavatyyppit.
registerSearchComponentsKanavan otsikon hakukenttä: sovellusten alueet näkyvät, kun kenttä on tyhjä.
registerUserGuideDropdownMenuActionTietoja Antimatterista (sovelluksen sivupalkin alareunassa), kohdassa Ohje.
registerProductTäydet sivut tuotteen URL-osoitteessa perinteisessä sivukehyksessä ilman tuotevalikkoa: Fusionissa ei ole tuotevalikkoa eikä siinä luetella tuotteita, joten linkitä sivulle itse. Mikään sisällytetty sovellus ei rekisteröi tuotetta: Kanban, Ohjekirjat ja tekoälykeskustelu avautuvat niiden sivupaneelissa.
registerRootComponent, registerGlobalComponent, koukut kuten registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer, registerTranslationsToimivat klassisen käyttöliittymän tapaan.
registerAdminConsolePlugin, registerAdminConsoleCustomSettingJärjestelmäkonsoli, joka on klassinen molemmissa käyttöliittymissä.

Mitä Fusion ei näytä tai aja

  • registerPostDropdownMenuComponent (komponentti viestin valikossa) ja registerPostCardTypeComponent (viestin kortti oikeanpuoleisessa paneelissa) eivät näy Fusionin päänäkymissä. registerProductSwitcherMenuItem ei tee mitään Fusionissa, jossa ei ole tuotevalikkoa (kirjaa varoituksen). Käytä ensimmäisen sijaan komentoa registerPostDropdownMenuAction.
  • registerMessageWillBeUpdatedHook ei aja, kun viestiä muokataan Fusionissa. Tarkista muokkaukset palvelimella MessageWillBeUpdated-koukulla.
  • registerActionAfterChannelCreation ajaa vain klassisesta kanavan luontiaikaruudusta, jonka Fusion avaa Lisää vaihtoehtoja… -kohdasta Luo kanava -ruudussa.
  • Sovelluspalkin komponentit näkyvät riippumatta supportedProductIds-arvosta.
  • Reitit, jotka on rekisteröity metodien registerNeedsTeamRoute ja registerCustomRoute kautta, säilyttävät klassisen sivukehyksen, kuten tuotteet.

Koukut, joita vain Antimatterissa on

Näitä rekisteröintimetodeja ei ole Mattermostissa. Tarkista, että metodi on olemassa ennen kutsua, jotta sovellus toimii sielläkin:

if (typeof registry.registerComposerMenuItem === 'function') {
    registry.registerComposerMenuItem({
        text: 'Create a poll',
        icon: <i className='icon icon-chart-bar'/>,
        fusionIcon: 'poll',
        action: ({channelId, rootId}) => openPollCreation(channelId, rootId),
    });
} else {
    registry.registerChannelHeaderButtonAction(icon, (channel) => openPollCreation(channel.id), 'Create a poll', 'Create a poll');
}
MetodiMitä se lisää
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender})Kohta viestikentän +-valikossa, molemmissa käyttöliittymissä. action saa parametrina {channelId, rootId}.
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker})Viestiruudun emojivalikkeen välilehti, kuten GIFit tai tarrat. Fusionissa order -arvon ollessa alle 10 välilehti sijoittuu Emojit-välilehden eteen. Komponentti saa parametreina channelId, rootId, filter, onFilterChange, onSelectDone, insertText, isFusion ja Fusionissa pickerKit (katso alla).
registerChannelViewPanel({matcher, component})Paneeli kanavan otsikon ja viestien välillä, kanaville, jotka matcher(state, channel) valitsee. Se voi piilottaa viestit ja kirjoitusruudun (setMessagesVisible), kuten äänikanavat tekevät.
registerSidebarChannelFooterComponent(component)Rivi kanavan alla sivupalkissa, kuten puhelun osallistujat. Se saa parametrikseen channel.
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender})Vain Fusionissa: Integraatiot -sivun kohde, joka sijaitsee mukautettujen emojien vieressä. GIFit-sovellus lisää sinne omat GIFinsä ja tarransa.

Lisää ja hallitse näkymiä emojivalikkeeessa

Fusionissa emojivalikkeen välilehti saa pickerKit -parametrin: Emojit-välilehden omia lisäys- ja hallintanäkymiä käyttävät komponentit, jotta välilehden näkymät näyttävät samalta ja pysyvät valikkeen sisällä. GIFit- ja Memes-sovellukset käyttävät sitä GIFien, tarran ja memepohjien lisäämiseen ja hallintaan. Parametri sisältää version (1), hookit usePickerView ja useOnEscape sekä komponentit PickerViewButtons (hakuikkunan vieressä olevat + ja hallinta-napit), PickerViewFrame (näkymä, jossa on taaksepäin-nuoli), PickerNotice, PickerField, PickerSearch, PickerDropZone ja PickerManageList. Escape-näppäin palauttaa näkymästä välilehden ruudukkoon. Tarkista, että parametri on olemassa: muut isäntäympäristöt jättävät sen pois, jolloin välilehti käyttää omia ikkunoitaan. Tyypit löytyvät tiedostosta webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) ja komponentit tiedostosta webapp/fusion/src/fusion/popovers/picker_views.tsx.

Kirjoitusalueen tilat

Fusionissa registerComposerMode({id, label, fusionIcon, placeholder, sendLabel, component, shouldRender}) lisää viestien kirjoittamiselle uuden tavan, kuten Kyselyt tekee kyselyille. Tila tarjotaan kirjoitusalueen +-valikossa sen label-arvon alla. Kun tila on valittu, kirjoitusalue säilyttää tekstikenttänsä (tilan placeholder-arvolla: kyselyyn kysymys), näyttää sen alla component-komponenttisi ja palkin, jossa on tilan nimi ja Peruuta-painike; Lähetä käyttää sendLabel-arvoa ja suorittaa lähetyksesi tekstin julkaisemisen sijaan.

  • Komponentti saa vastaan channelId, rootId (ketju vastauskentässä), message (kirjoitusalueen teksti), setSubmit ja onCancel (palaa tavalliseen viestiin, teksti säilyttäen).
  • Anna setSubmit-funktiolle funktio, jota kutsutaan kirjoitusalueen tekstillä ja joka ratkeaa tyhjäksi (tai tyhjäksi merkkijonoksi) lähetyksen jälkeen: kirjoitusalue tyhjennetään ja palaa tavalliseen viestiin. Jos haluat näyttää virheen paikan päällä, ratkaise merkkijonona.
  • placeholder ja sendLabel ovat merkkijonoja tai funktioita react-intlin intl:stä. shouldRender(state, {channelId, rootId}) päättää, tarjoaako kirjoitusalue tilan.
  • Avataksesi tilan muualta, kuten kauttaviivakomennolla ilman argumentteja: window.dispatchEvent(new CustomEvent('am-composer-mode', {detail: {id, channelId, rootId}})).

Vain Fusionissa on kirjoitusalueen tiloja: tarkista, että rekisterissä on funktio, ja pidä oma dialogisi muuten. Metodi palauttaa tilan id:n, ja tila poistuu, kun sovellus poistetaan.

Paneeli uudessa ikkunassa

Fusion antaa registerRightHandSidebarComponent-komponentille kaksi lisäominaisuutta, jotta Avaa uuteen ikkunaan avaa paneelin siellä missä se oli, eikä sovelluksen etusivulla:

  • setPanelState(state): kutsu tätä, kun paneeli vaihtaa sijaintia, ja anna sille lyhyt merkkijono, jonka sovelluksesi määrittelee, kuten 'note/<id>' tai 'board/<id>/card/<id>', tai null, jos paneeli on etusivulla. Arvo siirretään ikkunan osoitteeseen, joten älä koskaan sisällytä siihen salaisuuksia. Tilat, jotka ovat pidempiä kuin 512 merkkiä tai sisältävät ohjausmerkkejä, hylätään.
  • initialPanelState: uuden ikkunan tila, eli tila, jossa paneeli oli, tai undefined. Tarkkaele sitä epäluotettavana syötteenä: nouta kohde uudelleen kirjautuneen henkilön nimellä ja näytä sovelluksen etusivu tai ”ei löytynyt”-näkymä, jos he eivät voi avata sitä.

Tila unohdetaan, kun paneeli suljetaan tai toisen sovelluksen paneeli vie sen tilalle. Jos haluat avata paneelin ikkunan itse, popoutRhsPlugin (myös window.WebappUtils.popouts-funktiolla) ottaa tilan valinnaisena viidentenä argumenttina. Muistiinpano, Valkotaulu, Tehtävälista, Kanban ja Ohjekirjat käyttävät tätä.

fusionIcon nimittää Fusionin ikoni-setin ikonia (esimerkiksi poll, sticker, calendar tai image; ks. webapp/fusion/src/fusion/components/icon). Fusion näyttää sen icon-ikonin sijaan, jotta kohde vastaa muita.

Asetukset

settings_schema -määrite plugin.json-tiedostossa kuvaa sovelluksen sivua kohdassa Järjestelmäkonsoli › Liiteohjelmat:

"settings_schema": {
  "header": "Forecasts come from the weather service below.",
  "settings": [
    {"key": "ServiceURL", "display_name": "Service URL", "type": "text", "default": "https://api.example.com"},
    {"key": "Units", "display_name": "Units", "type": "dropdown", "default": "metric",
     "options": [{"display_name": "Celsius", "value": "metric"}, {"display_name": "Fahrenheit", "value": "imperial"}]},
    {"key": "EnableAlerts", "display_name": "Severe weather alerts", "type": "bool", "default": false,
     "help_text": "Post alerts in the channels that follow a city."}
  ]
}

Asetustyypit: bool, text, longtext, number, dropdown, radio, generated (satunnainen salaisuus), username ja custom (piirretään komponentilla, jonka web-sovelluksen osa rekisteröi registerAdminConsoleCustomSetting -funktiolla). Asetukset voidaan ryhmitellä sections -ryhmiin.

Palvelinosa lukee ne rakenteeseen, jonka kentät vastaavat avaimia:

type configuration struct {
	ServiceURL   string
	Units        string
	EnableAlerts bool
}

func (p *Plugin) OnConfigurationChange() error {
	var cfg configuration
	if err := p.API.LoadPluginConfiguration(&cfg); err != nil {
		return err
	}
	p.setConfiguration(&cfg)
	return nil
}

Ylläpitäjät voivat myös asettaa ne asetustiedostoon kohdassa PluginSettings.Plugins.<app id>, avaimet pienin kirjaimin (ks. ylläpitäjän opas).

Käännökset

Antimatter on käännetty 37 kielelle, ja mukana toimitetut sovellukset ovat käännettyjä. Web-sovelluksen osa tekee sen näin:

  1. Kirjoita jokainen merkkijono React Intl -kirjastolla, ID:llä ja englanninkielisellä tekstillä: <FormattedMessage id='polls.create' defaultMessage='Create a poll'/> tai defineMessages. Lisää ID:hin etuliiteksi sovelluksesi nimi.
  2. Poista englanninkieliset merkkijonot tiedostoon webapp/i18n/en.json (mukana toimitetut sovellukset käyttävät formatjs extract -työkalua).
  3. Lisää yksi tiedosto per kieli sen viereen, samoin ID:llä: fr.json, de.json, pt-BR.json, zh-CN.json…
  4. Anna ne webbisovellukselle, joka kysyy käyttäjän kieltä:
    import fr from '../i18n/fr.json';
    import ptBR from '../i18n/pt-BR.json';
    
    const catalogs = {fr, 'pt-BR': ptBR};
    
    export function translationsFor(locale) {
        return catalogs[locale] || catalogs[locale.split('-')[0]] || {};
    }
    
    registry.registerTranslations(translationsFor);

Puuttuva merkkijono palautuu englanninkieliseen defaultMessage-arvoon. Palvelinpuolen lähettämille merkkijonoille (komentovastaukset, bottiviestit) pluginapi/i18n-paketti lukee pakettiin sisältyvät käännöstiedostot (esimerkiksi assets/i18n) ja antaa kääntäjän kullekin käyttäjälle hänen kielellään.

Käännä, asenna ja vianetsi

Tarvitset Go- ja Node.js-ympäristön (sovelluksen .nvmrc-tiedostossa määritetty versio). Sovelluksen hakemistossa:

KomentoToiminto
make distKääntää palvelinpuolen kaikille alustoille ja webbisovelluspuolen, ja kirjoittaa paketin polkuun dist/<app id>-<version>.tar.gz.
make testSuorittaa Go- ja JavaScript-testit.
make check-styleTarkistaa koodin laadun (golangci-lint, ESLint) ja TypeScript-tyypit.
make deployKääntää, asenna ja ottaa paketin käyttöön palvelimella.
make watch, make deploy-from-watchEnsimmäinen kääntää webbisovelluspuolen joka kerta, kun tallennat; toinen paketoima käännetyt osat ja asettaa ne palvelimelle.
make enable, make disable, make resetOta sovellus käyttöön, poista se käytöstä tai käynnistä se uudelleen palvelimella.
make logs, make logs-watchNäytä sovelluksen rivit palvelinlokkissa.
make attachLiittää Delve-vianetsin käynnissä olevaan palvelinosaan (käännä ensin AM_DEBUG=1 kanssa).

make deploy ja muut palvelinkomennot käyttävät paikallista tilaa koskevaa sokkelia, jos sellainen löytyy (/var/tmp/antimatter_local.socket tai AM_LOCALSOCKETPATH): aja ne palvelimen koneella, jossa paikallinen tila on päällä. Muuten ne kirjautuvat palvelimelle, jonka osoitteen antaa MM_SERVICESETTINGS_SITEURL, käyttäen AM_ADMIN_TOKEN-tai AM_ADMIN_USERNAME- ja AM_ADMIN_PASSWORD-tunnuksia. Käännöstyökalut eivät vielä lue AM_-nimistä asetusta palvelimen osoitteelle.

Asenna paketti käsin

  • Järjestelmäylläpitäjä sallii lataukset asetuksella AM_PLUGINSETTINGS_ENABLEUPLOADS=true (oletuksena pois käytöstä; Järjestelmäkonsolissa ei ole kytkintä).
  • Sitten Järjestelmäkonsoli › Liiteohjelmat › Liiteohjelmien hallinta › Lähetä liiteohjelma, tai amctl plugin add weather.tar.gz ja sen jälkeen amctl plugin enable com.example.weather.
  • Jos palvelimella on Vaadi lisäosan allekirjoitusta -asetus käytössä, se hyväksyy vain luotetulla avaimella allekirjoitetut pakettit; ks. Muiden sovellusten asennus.
Nopeita kehitysiteraatiosia kehityspalvelimelle varten aseta palvelimelle AM_SERVICESETTINGS_ENABLEDEVELOPER=true: virheet sisältävät silloin tarkemmat tiedot. Pakettien Makefilet kääntävät palvelinpuolen vain sille alustalle, jolla MM_SERVICESETTINGS_ENABLEDEVELOPER on määritetty shellissäsi.