Vytváření aplikací (pluginů)
Aplikace přidávají funkce do Antimatteru zevnitř: serverová část v Go, která se napojuje na server, a webová část v React, která přidává nabídky, panely, typy zpráv a stránky. Tato stránka ukazuje, jak je aplikace strukturována, s využitím přiložené aplikace Polls jako příkladu, a co se mění v rozhraní Fusion v Antimatteru.
Jak aplikace funguje
- Serverová část je program v Go. Server ho spustí jako samostatný proces a komunikuje s ním přes RPC: volá hooky aplikace (zpráva má být odeslána, byl spuštěn příkaz…) a aplikace volá plugin API serveru (vytvořit příspěvek, přečíst uživatele, uložit data…). Může také sloužit HTTP cesty pod
/plugins/<app id>/. - Webová část je JavaScript balíček načtený do prohlížeče spolu s webovou aplikací. Registruje React komponenty a callbacky v registru: tlačítko v nabídce, panel, způsob vykreslení typu zprávy.
- Kterákoli z částí je volitelná. Aplikace se instaluje jako balíček
.tar.gza systémoví administrátoři ji zapínají, vypínají a konfiguruji.
Antimatter spouští aplikace psané pro Mattermost a naopak, pokud aplikace používá pouze hooky, které mají obě. Viz Hooky, které má pouze Antimatter.
Struktura balíčku
Neexistuje samostatná šablona pro začátek: začněte od malé přiložené aplikace, jako je antimatter-plugin-polls nebo antimatter-plugin-todo, a změňte její ID a kód. Aplikace Polls má tuto strukturu:
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
Volitelné: složka public/, která se servíruje beze změny na adrese /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: jedinečné a trvalé; obvykle se používá obrácené doménové jméno. Určuje názvy cest, uložených nastavení a WebSocket událostí.version: sémantická verze. Přiložené aplikace ji vynechávají vplugin.json; jejich nástroj pro sestavení ji bere z nejnovějšího git taguv*.min_server_version: Antimatter hlásí12.0.0.settings_schema: stránka nastavení aplikace v Systémové konzoli (viz Nastavení).
make apply zkopíruje manifest do server/manifest.go a webapp/src/manifest.ts; make manifest-check ho ověří.
Serverová část
Serverová část importuje stejný Go modul jako aplikace Mattermost, github.com/mattermost/mattermost/server/public, z Go modulu proxy. Její main pouze spustí aplikaci:
package main
import "github.com/mattermost/mattermost/server/public/plugin"
func main() {
plugin.ClientMain(&Plugin{})
}
Typ Plugin obsahuje plugin.MattermostPlugin, což mu poskytuje p.API, a implementuje potřebné háčky:
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)
}
Běžné háčky
| Háček | Kdy se spustí |
|---|---|
OnActivate, OnDeactivate | Když je aplikace zapnuta nebo vypnuta, a když se server spouští a zastavuje. Příkazy a boty registrujte v OnActivate. |
OnConfigurationChange | Když se změní její nastavení; načtěte je pomocí p.API.LoadPluginConfiguration(&cfg). |
ServeHTTP | Požadavky na /plugins/<app id>/…. Server nastaví hlavičku Mattermost-User-Id, když požadavek pochází od přihlášeného uživatele; požadavky bez ní zamítněte, pokud nemají být veřejné. |
ExecuteCommand | Byl spuštěn příkaz, který aplikace registrovala. |
MessageWillBePosted, MessageWillBeUpdated | Před uložením zprávy: vraťte upravený příspěvek nebo důvod pro jeho zamítnutí. |
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeleted | Po události, pro vedlejší efekty. |
ReactionHasBeenAdded, ReactionHasBeenRemoved | Reakce. |
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreated | Změny členství a kanálů. Tým je komunita. |
FileWillBeUploaded | Před uložením souboru: změňte ho nebo ho zamítněte. |
OnPluginClusterEvent | Zpráva ze stejné aplikace na jiném serveru v clusteru. |
Úplný seznam s přesnými podpisy najdete v server/public/plugin/hooks.go; API je v server/public/plugin/api.go. Balíček pluginapi (server/public/pluginapi) obaluje API v uživatelsky přívětivějších pomocných funkcích.
Užitečné volání API
CreatePost,UpdatePost,SendEphemeralPost: publikujte jako bot aplikace nebo jako uživatel.EnsureBotUser(&model.Bot{Username, DisplayName}): jednou vytvoříte bot aplikace a získáte jeho ID.PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): pošle událost do webové aplikace. Přijde jakocustom_<app id>_poll_updated.OpenInteractiveDialog: otevře dialog.LogInfo,LogErrora podobné: zapisuje do serverového logu, označené ID aplikace.GetUser,GetChannel,HasPermissionToChannel: zkontrolujte, kdo co smí, než budete jednat jménem uživatele.
Aplikace běží na každém serveru v klastru. Uchovávejte stav v klíčově-hodnotovém úložišti nebo v databázi, ne pouze v paměti.
Služba AI
Server Antimatter volá modely AI pro aplikace prostřednictvím připojení k modelům, která nastavil administrátor (viz AI v administrátorském průvodci). Aplikace nikdy neuchovává klíč poskytovatele: pouze udává, pro koho a kde jedná, a server zkontroluje, zda má tato osoba v daném místě přístup k připojení, uplatní jeho limity a rozpočty, započítá tokeny na osobu i aplikaci a zaznamená volbu do auditního deníku bez obsahu.
| Metoda | Co dělá |
|---|---|
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest) | Doplnění chatu: zprávy, nástroje, strukturovaný výstup (JSONSchema). |
AIChatStream(…) | To samé, ale v proudu: čtěte Events proudu, dokud se kanál neuzavře, nebo ho Closete, aby se volba zastavila. |
AIEmbed(…, *ai.EmbedRequest) | Embeddingy textů. |
AITranscribe(…, *ai.TranscribeRequest) | Přepis řeči do textu. |
AIDecide(…, *ai.DecideRequest) | Typované dotazy na rozhodovací model (ano nebo ne, výběr, skóre) k textu. |
AIConnectionsForUser(userID, channelID, teamID) | Připojení, která osoba v daném místě může používat, včetně jejich modelů a funkcí, nikdy však klíčů. |
ConnectionID každé žádosti vybírá připojení a Model jeden z jeho modelů (prázdné pro výchozí model připojení). Operation je krátká značka pro záznamy o využití a audit, nikdy neobsahuje obsah. Minimální verze serveru je 11.11.
actingUserID berte pouze ze zdroje, který server ověřil: hlavička Mattermost-User-Id v žádosti do vašeho ServeHTTP, nebo uživatel z kontextu háčku (autor příspěvku, uživatel, který spustil příkaz). Nikdy ji neberte ze zprávy, payloadu webhooku, URL ani z žádosti jiné aplikace: vaša aplikace by pak utratila přístup jiného uživatele.Tyto metody a balíček ai (server/public/ai) existují pouze v kopii modulu od Antimatter, ne ve verzi publikované Mattermost. K jejich použití sestavujte proti server/public od Antimatter s řádkem replace ve vašem go.mod, např. replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public. Taková aplikace běží pouze na Antimatter.
Poskytování nástrojů agentům
Aplikace nabízí své vlastní nástroje agentům pomocí RegisterAITools([]*model.AIToolDefinition): název každého nástroje, jeho titul, popis, vstupní JSON schéma a typ (read, write nebo external_write), který určuje, zda jej agent může spustit samostatně podle své politiky (viz Nástroje v průvodci pro administrátory). Oprávnění jsou kontrolována na argumentu kanálu nebo komunity v daném volání, nebo na serveru, podle toho, co nástroj vyžaduje. Když agent nástroj použije, server zavolá hook ExecuteAITool(c, *model.AIToolExecution) *model.AIToolResult s ověřeným uživatelem, který požadavek podal, v poli UserId: jednejte pouze s jeho oprávněními, nikdy s oprávněními agenta. Nástroje jsou pojmenovány ve formátu <app id>.<name>; minimální verze serveru je 11.11; tyto metody a hook existují pouze v server/public aplikace Antimatter, stejně jako výše zmíněná AI služba. Aplikace s ID antimatter nebo ty, jejichž ID začíná na mcp., nemohou registrovat nástroje.
Ukládání dat
Každá aplikace má ve databázi serveru vlastní klíčově-hodnotové úložiště:
KVSet(key, value),KVGet(key),KVDelete(key): hodnoty jsou bajty, obvykle JSON. Klíče mají maximálně 150 znaků.KVSetWithExpiry(key, value, seconds): hodnota po uplynutí této doby zmizí.KVCompareAndSet(key, old, new)aKVSetWithOptionssAtomic: bezpečné aktualizace, když stejný klíč zapisuje více požadavků nebo serverů. Hlasování takto ukládá každý hlas a v případě konfliktu operaci opakuje.KVList(page, perPage): klíče, stránka po stránce.
Webová část aplikace
Balíček registruje třídu pomocí window.registerPlugin. Její initialize přijímá registr a Redux store:
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());
- Sdílené knihovny. Webová aplikace poskytuje React, ReactDOM, Redux, React Redux a React Intl: vyjmenujte je jako webpack
externals(React,ReactDOM,Redux,ReactRedux,ReactIntl) místo toho, abyste balíčkovali vlastní kopie. Vizwebpack.config.jsaplikace Hlasování. - Volání vaší serverové části. Pošlete požadavek na
${window.basename}/plugins/<app id>/…s možnostmi zClient4.getOptions()(zmattermost-redux/client): nesou hlavičky, které server potřebuje k přijetí požadavku z prohlížeče. - Váš vlastní stav.
registerReducerpřidá reducer, který se ukládá podstate['plugins-<app id>']. - Typy. Další metody registru v Antimatter nejsou součástí zveřejněných typů Mattermost: Hlasování deklaruje registr, který používá, v
webapp/src/types/host.ts.
Metody registru a jejich parametry jsou zdokumentovány v kódu, v webapp/fusion/src/plugins/registry.ts (Fusion) a webapp/channels/src/plugins/registry.ts (klasické).
Podpora rozhraní Fusion
Antimatter má dvě webová rozhraní: Fusion, které je výchozí, a klasické. Oba načítají stejné balíčky aplikací a mají stejný registr, ale Fusion si mnoho věcí vykresluje samo a komponenty pluginů umísťuje svým vlastním způsobem. Otestujte svou aplikaci v obou.
Zjištění rozhraní
Před načtením jakékoli aplikace nastaví obě rozhraní window.antimatterWebUI na 'fusion' nebo 'classic' a stejnou hodnotu na kořenový prvek stránky jako data-am-web-ui. V Mattermost není žádná z nich nastavena.
export function isFusionUI(): boolean {
return window.antimatterWebUI === 'fusion' || document.documentElement.dataset.amWebUi === 'fusion';
}
Sdílené aplikace toto využívají k odlišnému vykreslování. Aplikace Hlasování vykresluje karty hlasování ve stylu Fusionu a v Fusionu je hlasování napsáno přímo v kompozitoru (jeden z režimů kompozitoru) namísto v dialogovém okně. Aplikace Hovory a Hlasové kanály vynechávají komponenty bočního panelu a vyskakovacích oznámení, které Fusion nahrazuje vlastním rozhraním hovorů. Aplikace AI chat umisťuje své akce AI do nabídky zprávy, jako skupinu pod Další akce, namísto nástrojové lišty zobrazované při najetí kurzorem. Vlastní CSS třídy Fusionu (s předponou am-) a jeho vrstva dialogových oken (element am-layer) jsou to, co tyto aplikace využívají k přizpůsobení rozhraní; nejedná se o zdokumentované, stabilní API.
Kde Fusion zobrazuje komponenty pluginů
| Metoda registru | Kde se v Fusionu zobrazí |
|---|---|
registerAppBarComponent, registerChannelHeaderButtonAction | Lišta aplikací, sloupec ikon na pravém okraji, mezi vaším avatarom a tlačítkem O aplikaci Antimatter. Tam se také umísťují tlačítka v hlavičce kanálu, nikoli v samotné hlavičce. Skryje se, když systémový administrátor zapne Vypnout lištu aplikací (ExperimentalSettings.DisableAppBar, výchozí stav je vypnuto). |
registerRightHandSidebarComponent | Pravý panel. Jeho hlavička je součástí Fusionu a je stejná pro všechny aplikace: ikona a název aplikace (registrovaný titulek, pokud se vykresluje pouze text, jinak popisek v liště aplikací nebo název z manifestu), poté Obnovit velikost panelu (po změně velikosti), Otevřít v novém okně a Zavřít. Titulek, který vykresluje cokoliv jiného (ovládací prvek, odkaz, obrázek), je vynechán, proto své vlastní ovládací prvky aplikace vykreslete přímo v panelu, například v úzkém řádku nahoře. Panel lze změnit tažením za jeho okraj. Viz Panel v novém okně. |
registerChannelHeaderIcon | Ikony v hlavičce kanálu, za tlačítky pro hovory; na mobilních telefonech v menu Více v hlavičce. |
registerCallButtonAction | Tlačítko pro hovor v hlavičce kanálu; několik poskytovatelů sdílí menu Další způsoby, jak zavolat. |
registerPostDropdownMenuAction | Menu Akce se zprávou (⋯) zprávy, v jeho podmenu Další akce; také v menu Akce s vláknem panelu vlákna, pod Další akce. Fusion vykresluje ikonu aplikace před každou akcí, v šedé: vlastní ikonu pro integrované aplikace, jinak ikonu, kterou aplikace zobrazuje v liště aplikací, jinak neutrální ikonu. Prvek bez textu na začátku textu akce (ikona, kterou aplikace vykresluje sama) je skryt. |
registerPostDropdownSubMenuAction | Skupina položek ve stejné podnabídce Další akce, umístěná za jednotlivými akcemi, oddělená linkou a bez nadpisu. Žádná aplikace nezíská vlastní položku v nabídce zprávy. |
registerPostActionComponent | Nabídka zprávy při najetí kurzorem, před tlačítkem ⋯. |
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponent | Samotná zpráva: její tělo, pod jejím textem, za jejím časem a na místě náhledů odkazů. |
registerChannelHeaderMenuAction | Menu Možnosti kanálu kanálu (⋯ u kanálu v bočním panelu, nebo pravým tlačítkem myši), jako položky s ikonou zásuvky. |
registerMainMenuAction | Menu komunity (název komunity nahoře v seznamu kanálů), pod Další akce, seskupeno podle aplikace. |
registerSidebarBrowseOrAddChannelMenuAction | Menu komunity, za Vytvořit kanál a Vytvořit kategorii. |
registerFileUploadMethod | Menu + v kompozitoru (Přidat do zprávy), za Nahrát soubor. |
registerPostEditorActionComponent | Formátovací lišta v kompozitoru, když je formátování zobrazeno. |
registerAIActionMenuItemComponent | Menu AI v kompozitoru. |
registerFileDropdownMenuAction, registerFilePreviewComponent | Menu možností souboru a náhled souboru. |
registerUserSettings | Profil a nastavení, jedna záložka na aplikaci pod nadpisem Pluginy. |
registerChannelSettingsTab | Dialog nastavení kanálu, pod nadpisem Aplikace. |
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponent | Karta profilu, která se zobrazí, když kliknete na jméno nebo avatar. |
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponent | Horní část seznamu kanálů komunity, vedle názvu kanálu, ikony kanálu a spodní části bočního panelu komunity vlevo. |
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholder | Začátek historie kanálu, horní část seznamu zpráv, čára nepřečtených zpráv, nad editorem zpráv a placeholder editoru. |
registerChannelTypeOption | Typy kanálů v dialogu Vytvořit kanál. |
registerSearchComponents | Vyhledávací pole v hlavičce kanálu: rozsahy aplikace se zobrazí, když je prázdné. |
registerUserGuideDropdownMenuAction | O aplikaci Antimatter (spodní část bočního panelu aplikace), pod Nápověda. |
registerProduct | Celé stránky na URL produktu, v klasickém rámu stránky, bez nabídky produktů: Fusion žádnou nabídku produktů nemá a nikde je nevytváří, proto odkazujte na stránku sami. Žádná sdílená aplikace neregistruje produkt: Kanban, Playbooky a AI chat se otevírají v bočních panelech. |
registerRootComponent, registerGlobalComponent, hooky jako registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer, registerTranslations | Fungují stejně jako v klasickém rozhraní. |
registerAdminConsolePlugin, registerAdminConsoleCustomSetting | Systémová konzole, která je v obou rozhraních klasická. |
Co Fusion nezobrazuje ani nespouští
registerPostDropdownMenuComponent(komponenta v nabídce zprávy) aregisterPostCardTypeComponent(karta příspěvku v pravém panelu) se ve hlavních zobrazeních Fusionu nezobrazují.registerProductSwitcherMenuItemve Fusionu nic nedělá, protože Fusion nemá nabídku produktů (zapíše se varování). Místo prvního funkce použijteregisterPostDropdownMenuAction.registerMessageWillBeUpdatedHookse nespustí, když se zpráva upraví v Fusion. Úpravy ověřujte na serveru pomocí hookuMessageWillBeUpdated.registerActionAfterChannelCreationse spouští pouze z klasického dialogu pro vytváření kanálu, který Fusion otevírá z Další možnosti… v dialogu Vytvořit kanál.- Komponenty lišky aplikace se zobrazují bez ohledu na
supportedProductIds. - Cesty z
registerNeedsTeamRoutearegisterCustomRoutesi zachovávají klasický rámec stránky, stejně jako produkty.
Hooky, které má pouze Antimatter
Tyto metody registru neexistují v Mattermost. Před voláním metody ověřte, že existuje, aby aplikace fungovala i tam:
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');
}
| Metoda | Co přidává |
|---|---|
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender}) | Položka v menu + v poli pro zprávu, v obou rozhraních. action přijímá {channelId, rootId}. |
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker}) | Karta výběru emoji v poli pro zprávu, například GIFy nebo samolepky. V Fusion se karty s order menším než 10 zobrazí před kartou Emoji. Komponenta přijímá channelId, rootId, filter, onFilterChange, onSelectDone, insertText, isFusion a v Fusion pickerKit (viz níže). |
registerChannelViewPanel({matcher, component}) | Panel mezi záhlavím kanálu a zprávami, určený pro kanály, které vybere matcher(state, channel). Může skrýt zprávy i editor (setMessagesVisible), stejně jako to dělají hlasové kanály. |
registerSidebarChannelFooterComponent(component) | Řádek pod kanálem v bočním panelu, například lidé v jeho hovoru. Přijímá channel. |
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender}) | Pouze Fusion: položka na stránkách Integrace, vedle vlastních emoji. Aplikace GIFs tam přidá své vlastní GIFy a samolepky. |
Přidat a spravovat pohledy ve výběru emoji
Ve Fusion se tabulce výběru emoji přidává prop pickerKit: komponenty, které tabulka Emoji používá pro vlastní zobrazení přidávání a správy, aby se pohledy tabulky podobaly a zůstaly uvnitř výběru. Aplikace GIFs a Memes ho používají k přidávání a správě GIFů, samolepek a šablon memů. Obsahuje version (1), hooky usePickerView a useOnEscape a komponenty PickerViewButtons (tlačítka + a správy vedle vyhledávacího pole), PickerViewFrame (pohled se šipkou zpět), PickerNotice, PickerField, PickerSearch, PickerDropZone a PickerManageList. Klávesa Escape se vrací z pohledu do mřížky tabulky. Zkontrolujte, že prop je přítomen: jiní hostitelé ho vynechávají a tabulka pak používá vlastní dialogy. Typy jsou v webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) a komponenty v webapp/fusion/src/fusion/popovers/picker_views.tsx.
Režimy kompozitoru
V aplikaci Fusion přidá registerComposerMode({id, label, fusionIcon, placeholder, sendLabel, component, shouldRender}) další způsob psaní zprávy v kompozitoru, podobně jako to dělá aplikace Hlasování pro hlasování. Tento režim je nabízen v nabídce + kompozitoru pod svým label. Po výběru si kompozitor zachová textové pole (s placeholder daného režimu, např. otázkou v hlasování), zobrazí pod ním váš component a lištu s názvem režimu a tlačítkem Zrušit; tlačítko Odeslat použije sendLabel a spustí váš odesílací skript místo odeslání textu.
- Komponenta přijímá
channelId,rootId(vlákno v poli pro odpověď),message(text kompozitoru),setSubmitaonCancel(návrat na běžnou zprávu se zachováním textu). - Funkci
setSubmitpředávejte funkci, která je volána s textem kompozitoru a po odeslání se vyhodnotí na nic (nebo prázdný řetězec): kompozitor se pak vymaže a vrátí se do stavu běžné zprávy. Pokud se vyhodnotí na řetězec, zobrazí se na místě jako chyba. placeholderasendLabeljsou řetězce nebo funkce využívajícíintlz knihovny react-intl.shouldRender(state, {channelId, rootId})rozhoduje o tom, zda kompozitor nabízí daný režim.- Pro otevření režimu z jiného místa, například pomocí příkazu s lomítkem bez argumentů:
window.dispatchEvent(new CustomEvent('am-composer-mode', {detail: {id, channelId, rootId}})).
Režimy kompozitoru jsou dostupné pouze ve Fusionu: zkontrolujte, zda registr tuto funkci obsahuje, a pokud ne, ponechte si vlastní dialog. Metoda vrací id režimu a režim je odstraněn při odebrání aplikace.
Panel v novém okně
Fusion předává komponentě registrované pomocí registerRightHandSidebarComponent dva další props, aby možnost Otevřít v novém okně otevřela panel tam, kde byl, nikoli na domovské stránce aplikace:
setPanelState(state): zavolejte ho, když se panel přesune, s krátkým řetězcem, který vaša aplikace definuje, např.'note/<id>'nebo'board/<id>/card/<id>', nebonullna domovské stránce. Hodnota se zapíše do adresy okna, takže do ní nikdy neukládejte tajná data. Stav delší než 512 znaků nebo obsahující ovládací znaky se zahodí.initialPanelState: v novém okně je to stav, který panel měl, neboundefined. Považujte ho za nedůvěryhodný vstup: položku znovu načtěte jako přihlášená osoba a pokud ji nemůže otevřít, zobrazte domovskou stránku aplikace nebo pohled „položka nenalezena“.
Stav se zapomene, když se panel zavře nebo ho nahradí panel jiné aplikace. Chcete-li okno panelu otevřít sami, použijte popoutRhsPlugin (který je také v window.WebappUtils.popouts); stav přijímá jako volitelný pátý argument. Používají ho Poznámky, Tabule, Úkoly, Kanban a Playbooky.
fusionIcon určuje ikonu z sady ikon Fusion (například poll, sticker, calendar nebo image; viz webapp/fusion/src/fusion/components/icon). Fusion ji zobrazí místo icon, aby se položka ladila s ostatními.
Nastavení
settings_schema v plugin.json popisuje stránku aplikace v Systémová konzole › Pluginy:
"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."}
]
}
Typy nastavení: bool, text, longtext, number, dropdown, radio, generated (náhodný tajný klíč), username a custom (vykreslené komponentou, kterou webová část aplikace zaregistruje pomocí registerAdminConsoleCustomSetting). Nastavení lze seskupit do sections.
Serverová část je načte do struktury, jejíž pole odpovídají klíčům:
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
}
Administrátoři je mohou nastavit i v konfiguraci, pod PluginSettings.Plugins.<app id>, s klíči ve小 písmenách (viz průvodce pro administrátory).
Překlady
Antimatter je přeložen do 37 jazyků, stejně jako přibalené aplikace. Webová část to dělá takto:
- Každý řetězec pište pomocí React Intl, s ID a jeho anglickým textem:
<FormattedMessage id='polls.create' defaultMessage='Create a poll'/>nebodefineMessages. ID předčínejte názvem vaší aplikace. - Vyextrahujte anglické řetězce do
webapp/i18n/en.json(přibalené aplikace používajíformatjs extract). - Přidejte jeden soubor pro každý jazyk vedle něj, se stejnými ID:
fr.json,de.json,pt-BR.json,zh-CN.json… - Předá je webové aplikaci, která se uživatele zeptá na jeho jazyk:
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);
Chybějící řetězec se vrátí na anglický defaultMessage. U řetězců, které posílá serverová část (odpovědi na příkazy, zprávy botů), balíček pluginapi/i18n načte soubory s překlady dodané v balíčku (například assets/i18n) a poskytne lokalizátor v jazyce každého uživatele.
Sestavení, instalace a ladění
Budete potřebovat Go a Node.js (verzi uvedenou v souboru .nvmrc aplikace). V složce aplikace:
| Příkaz | Co dělá |
|---|---|
make dist | Sestaví serverovou část pro všechny platformy a webovou aplikaci a zapíše balíček do dist/<app id>-<version>.tar.gz. |
make test | Spustí testy Go a JavaScript. |
make check-style | Zkontroluje kód (golangci-lint, ESLint) a ověří typy TypeScript. |
make deploy | Sestaví, poté nainstaluje a zapne balíček na serveru. |
make watch, make deploy-from-watch | První příkaz při každém uložení sestaví webovou aplikaci; druhý sestavení zabalí a nainstaluje na server. |
make enable, make disable, make reset | Zapne, vypne nebo restartuje aplikaci na serveru. |
make logs, make logs-watch | Zobrazí řádky aplikace v serverovém logu. |
make attach | Připojí ladící nástroj Delve ke spuštěné serverové části (nejprve sestavte s AM_DEBUG=1). |
make deploy a ostatní serverové příkazy používají místní režim socketu, pokud ho najdou (/var/tmp/antimatter_local.socket, nebo AM_LOCALSOCKETPATH): spustíte je na stroji serveru s zapnutým místním režimem. Jinak se přihlásí na server určený proměnnou MM_SERVICESETTINGS_SITEURL pomocí AM_ADMIN_TOKEN, nebo AM_ADMIN_USERNAME a AM_ADMIN_PASSWORD. Sestavovací nástroje zatím nečtou proměnnou AM_ pro adresu serveru.
Ruční instalace balíčku
- Systémový administrátor povolí nahrávání pomocí
AM_PLUGINSETTINGS_ENABLEUPLOADS=true(výchozí je vypnuto; v Systémové konzoli není přepínač). - Pak Systémová konzole › Pluginy › Správa pluginů › Nahrát plugin, nebo
amctl plugin add weather.tar.gza potéamctl plugin enable com.example.weather. - Pokud má server zapnuté Vyžadovat podpis pluginu, přijímá pouze balíčky podepsané klíčem, kterému důvěřuje; viz Instalace dalších aplikací.
AM_SERVICESETTINGS_ENABLEDEVELOPER=true: chyby pak nesou podrobnosti. Makefiles balíčkových aplikací sestaví serverovou část pouze pro vaši platformu, pokud je ve vašem shellu nastavena proměnná MM_SERVICESETTINGS_ENABLEDEVELOPER.