Alkalmazások (bővítmények) írása
Az alkalmazások belülről bővítik az Antimattert: egy Go nyelven írt szerverrész, amely a szerverbe horgonyozódik, és egy React nyelven írt webalkalmazásrész, amely menüket, paneleket, üzenettípusokat és oldalakat ad hozzá. Ez az oldal a csatolt Polls-alkalmazás példáján mutatja be, hogyan épül fel egy alkalmazás, és mi változik az Antimatter Fusion-felületén.
Hogyan működik egy alkalmazás
- A szerverrész egy Go program. A szerver külön folyamatként indítja el, és RPC-n keresztül kommunikál vele: meghívja az alkalmazás horgonyait (pl. egy üzenet即将 beküldésre kerül, egy parancs lefutott…), az alkalmazás pedig a szerver bővítmény-API-ját használja (pl. bejegyzés létrehozása, felhasználó olvasása, adatok tárolása…). HTTP útvonalakat is szolgálhat a
/plugins/<app id>/alatt. - A webalkalmazásrész egy JavaScript-csomag, amelyet a böngésző betölt a webalkalmazással együtt. A rejiszterben regisztrál React-komponenseket és visszahívásokat: egy gombot a menüben, egy panelt, egy üzenettípus megjelenítési módját.
- Bármelyik rész opcionális. Az alkalmazás egy
.tar.gzcsomagként települ, a rendszeradminisztrátorok pedig engedélyezik, letiltják és konfigurálják.
Az Antimatter futtathat Mattermost-nak írt alkalmazásokat, és fordítva, amennyiben az alkalmazás csak olyan horgonyokat használ, amelyek mindkettőben léteznek. Lásd: Csak az Antimatterben lévő horgonyok.
A csomag szerkezete
Nincs külön kezdősablon: induljon egy kicsi, csatolt alkalmazásból, például a antimatter-plugin-polls vagy a antimatter-plugin-todo alkalmazásból, és módosítsa annak azonosítóját és kódját. A Polls szerkezete így néz ki:
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
Opcionális: public/ mappa, amely a /plugins/<app id>/public/ alatt szolgálja ki a fájlokat változatlanul.
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: egyedi és állandó; általában fordított domainnév. Ez nevezi meg az útvonalakat, a tárolt beállításokat és a WebSocket-eseményeket.version: szemantikus verzió. A csatolt alkalmazások nem adják meg aplugin.json-ban; a build-eszköz a legutóbbiv*git-címkéből veszi.min_server_version: az Antimatter12.0.0verziót jelent.settings_schema: az alkalmazás beállításai a Rendszerkonzolon (lásd Beállítások).
A make apply parancs a manifestet a server/manifest.go és a webapp/src/manifest.ts fájlba másolja; a make manifest-check parancs pedig validálja.
A szerverrész
A szerverrész ugyanazt a Go-modult importálja, mint a Mattermost-alkalmazások, a github.com/mattermost/mattermost/server/public modult a Go-modul proxy-ról. A main függvény csak elindítja az alkalmazást:
package main
import "github.com/mattermost/mattermost/server/public/plugin"
func main() {
plugin.ClientMain(&Plugin{})
}
A Plugin típus beágyazza a plugin.MattermostPlugin típust, amely biztosítja a p.API hozzáférést, és megvalósítja a szükséges hookokat:
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)
}
Gyakori hookok
| Hook | Amikor fut |
|---|---|
OnActivate, OnDeactivate | Amikor az alkalmazás engedélyezve vagy letiltva, valamint amikor a szerver elindul és leáll. A parancsokat és botokat a OnActivate hookban kell regisztrálni. |
OnConfigurationChange | Amikor a beállítások megváltoznak; a p.API.LoadPluginConfiguration(&cfg) hívással tölthetők be. |
ServeHTTP | Kérések a /plugins/<app id>/… útvonalra. A szerver beállítja a Mattermost-User-Id fejlécet, ha a kérés bejelentkezett felhasználótól érkezik; utasítsa vissza azokat a kéréseket, amelyeknél ez a fejléc hiányzik, hacsak nem nyilvánosak. |
ExecuteCommand | Amikor egy az alkalmazás által regisztrált parancs fut le. |
MessageWillBePosted, MessageWillBeUpdated | Mielőtt egy üzenet elmentésre kerül: módosított bejegyzést vagy elutasítás okát adja vissza. |
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeleted | Utólag, mellékhatások végrehajtásához. |
ReactionHasBeenAdded, ReactionHasBeenRemoved | Reakciók. |
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreated | Taglétiségi és csatornaváltozások. A csapat egy közösség. |
FileWillBeUploaded | Mielőtt egy fájl tárolásra kerül: módosítsa vagy utasítsa vissza. |
OnPluginClusterEvent | Üzenet ugyanazon alkalmazástól egy klaszter másik szerveréről. |
A teljes lista, a pontos aláírásokkal, a server/public/plugin/hooks.go fájlban található; az API a server/public/plugin/api.go fájlban. A pluginapi csomag (server/public/pluginapi) barátságosabb segédfüggvényekkel burkolja be az API-t.
Hasznos API-hívások
CreatePost,UpdatePost,SendEphemeralPost: bejegyzés küldése az alkalmazás botjaként vagy felhasználóként.EnsureBotUser(&model.Bot{Username, DisplayName}): egyszeri bot létrehozása az alkalmazás számára és annak azonosítójának lekérése.PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): esemény küldése a webalkalmazásnak. Acustom_<app id>_poll_updatednéven érkezik meg.OpenInteractiveDialog: párbeszéd megnyitása.LogInfo,LogErrorés társaik: írás a szerver naplófájlba, az alkalmazás azonosítójával címkézve.GetUser,GetChannel,HasPermissionToChannel: ellenőrzés, ki mit tehet, mielőtt felhasználó nevében cselekszik.
Egy alkalmazás a klaszter minden szerverén fut. Az állapotot tárolja a kulcs-érték tárolóban vagy az adatbázisban, ne csak a memóriaban.
Az AI-szolgáltatás
Az Antimatter szervere AI-modelleket hív meg az alkalmazások számára, az adminisztrátor által beállított modellkapcsolatokon keresztül (lásd AI az adminisztrátori útmutatóban). Egy alkalmazás sosem tárol szolgáltatói kulcsot: megadja, kinek nevében és hol hajt végre műveletet, a szerver pedig ellenőrzi, hogy az adott felhasználó használhatja-e ott a kapcsolatot, alkalmazza a korlátokat és kereteket, a tokeneket pedig az adott felhasználó és az alkalmazás számlájára írja, a hívás tartalmának rögzítése nélkül.
| Metódus | Mire szolgál |
|---|---|
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest) | Csevegés-befejezés: üzenetek, eszközök, strukturált kimenet (JSONSchema). |
AIChatStream(…) | Ugyanez áramlással: olvasd a stream Events elemeit, amíg a csatorna nem záródik, vagy állítsd le a hívást a Close metódussal. |
AIEmbed(…, *ai.EmbedRequest) | Szövegek beágyazása (embeddings). |
AITranscribe(…, *ai.TranscribeRequest) | Beszéd szöveggé alakítása. |
AIDecide(…, *ai.DecideRequest) | Típusos kérdések egy döntéshozatali modellhez (igen vagy nem, választás, pontszám) egy szöveggel kapcsolatban. |
AIConnectionsForUser(userID, channelID, teamID) | Azok a kapcsolatok, amelyeket egy felhasználó ott használhat, modellekkel és képességekkel, de soha kulcsokkal. |
Minden kérés ConnectionID mezője választja ki a kapcsolatot, a Model pedig annak egy modeljét (üresen a kapcsolat alapértelmezett modeljét jelöli). Az Operation egy rövid címké a használati és audit-nyilvántartásokhoz, soha nem tartalmaz tartalmat. Ezek minimális szerververziója 11.11.
actingUserID értékét csak olyan forrásból vedd fel, amelyet a szerver hitelesített: a Mattermost-User-Id fejléc a ServeHTTP felé érkező kérésben, vagy a hurok kontextusában lévő felhasználó (a bejegyzés szerzője, vagy az a felhasználó, aki egy parancsot futtatott). Soha ne vedd fel egy üzenetből, webhook-teherből, URL-ből vagy egy másik alkalmazás kéréséből: így az alkalmazásod mások hozzáférését használná fel.Ezek a metódusok és az ai csomag (server/public/ai) csak az Antimatter saját modulmásolatában létezik, nem a Mattermost által kiadott verzióban. Használatukhoz az Antimatter server/public könyvtára ellen kell fordítani, egy replace sorral a go.mod fájlban, például: replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public. Ilyen alkalmazás csak Antimatter-en fut.
Adattárolás
Minden alkalmazásnak van saját kulcs-érték tárolója a szerver adatbázisában:
KVSet(key, value),KVGet(key),KVDelete(key): az értékek bájtok, általában JSON. A kulcsok legfeljebb 150 karakter hosszúak.KVSetWithExpiry(key, value, seconds): az érték eltűnik az adott idő elteltével.KVCompareAndSet(key, old, new)ésKVSetWithOptionsAtomicopcióval: biztonságos frissítések, ha több kérés vagy szerver ír ugyanarra a kulcsra. A Szavazás így ment el minden szavazást, és újrapróbálja a konfliktus esetén.KVList(page, perPage): a kulcsok, oldalanként.
A webalkalmazás rész
A csomag egy osztályt regisztrál a window.registerPlugin segítségével. Az initialize metódus megkapja a registry-t és a Redux store-t:
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());
- Megosztott könyvtárak. A webalkalmazás biztosítja a Reactet, a ReactDOMot, a Reduxot, a React Reduxot és a React Intlt: ezeket a webpack
externalslistájába kell felvenni (React,ReactDOM,Redux,ReactRedux,ReactIntl), nem pedig saját másolatokat csomagolni. Lásd a Szavazáswebpack.config.jsfájlját. - A szerveri rész hívása. A
${window.basename}/plugins/<app id>/…URL-t aClient4.getOptions()(amattermost-redux/client-ből) által visszaadott opciókkal kell lekérni: ezek tartalmazzák a fejléceket, amelyeket a szervernek szüksége van a böngészőből érkező kérések elfogadásához. - Saját állapot. A
registerReducerhozzáad egy reducer-t, amely astate['plugins-<app id>']alatt tárolódik. - Típusok. Az Antimatter extra registry-metódusai nem szerepelnek a Mattermost közzétett típusaiban: a Szavazás a
webapp/src/types/host.tsfájlban deklarálja a használt registry-t.
A registry metódusai és paraméterei a kódban vannak dokumentálva, a webapp/fusion/src/plugins/registry.ts (Fusion) és a webapp/channels/src/plugins/registry.ts (klasszikus) fájlokban.
A Fusion felület támogatása
Az Antimatternek két webes felülete van: a Fusion (az alapértelmezett) és a klasszikus. Mindkettő ugyanazokat az alkalmazáscsomagokat tölti be, és ugyanazt a registry-t használja, de a Fusion sok elemet saját maga rajzol, és a plugin komponenseket saját módon helyezi el. Tesztelje az alkalmazását mindkét felületen.
A felület azonosítása
Minden alkalmazás betöltése előtt mindkét felület beállítja a window.antimatterWebUI értékét 'fusion'-ra vagy 'classic'-ra, és ugyanezt az értéket a data-am-web-ui attribútumként is a lap gyökérelemére. A Mattermostban egyik sem van beállítva.
export function isFusionUI(): boolean {
return window.antimatterWebUI === 'fusion' || document.documentElement.dataset.amWebUi === 'fusion';
}
A csatolt alkalmazások ezt használják a megjelenítés eltérő formában történő megjelenítésére. A Szavazás alkalmazás a szavazási kártyáit és a létrehozási párbeszédablakot a Fusion stílusában rajzolja meg, és a Fusionban a /poll parancs saját párbeszédablakát nyitja meg. A Hívások és a Hangcsatornák kihagyják az oldalsávot és a toast-komponenseket, amelyeket a Fusion a saját hívásfelületével helyettesít. Az Ügynökök alkalmazás a mesterséges intelligencia műveleteit az üzenet menüjébe helyezi, a További műveletek csoportjába, nem pedig a lebegő eszköztáblába. A Fusion saját CSS-osztályai (az am- előtaggal) és a párbeszédablak-rétege (az am-layer elem) azok, amelyeket ezek az alkalmazások a felület illesztésére használnak; ezek nem dokumentált, stabil API-k.
Ahol a Fusion a bővítménykomponenseket megjeleníti
| Regisztrációs metódus | Ahol jelenik meg a Fusionban |
|---|---|
registerAppBarComponent, registerChannelHeaderButtonAction | Az app-sáv, a jobb szélen lévő ikonok oszlopa, az avatarod és az Az Antimatter névjegye gomb között. Ide kerülnek a csatorna-fejléc gombjai is, nem a csatorna-fejlécbe. Rejtve van, ha a rendszeradminisztrátor bekapcsolja az Apps Bar letiltása beállítást (ExperimentalSettings.DisableAppBar, alapértelmezetten ki). |
registerRightHandSidebarComponent | A jobb oldali panel. Az emberek a szélét húzva átméretezhetik, és új ablakban megnyithatják. Ha az alkalmazás egyben termék is, a panel a Megnyitás teljes oldalként lehetőséget kínálja. Lásd: A panel új ablakban. |
registerChannelHeaderIcon | Ikonok a csatorna-fejlécben, a hívás gombok után; mobilon a fejléc További menüjében. |
registerCallButtonAction | A csatorna-fejléc hívás gombja; több szolgáltató is megosztja a Egyéb hívási módok menüt. |
registerPostDropdownMenuAction | Az üzenet Üzenet műveletek (⋯) menüje, a További műveletek almenujában; valamint az üzenetszál panel Üzenetszál műveletei menüjében, a További műveletek alatt. A Fusion szürke színnel rajzolja meg az alkalmazás ikonját minden művelet előtt: a csatolt alkalmazások saját ikonját, egyébként pedig azt az ikont, amelyet az alkalmazás az alkalmazás-sínen mutat, vagy ha ez sincs, egy semleges ikont. Egy elem, amely nem tartalmaz szöveget a művelet szövegének elején (egy ikon, amelyet az alkalmazás maga rajzol), rejtve marad. |
registerPostDropdownSubMenuAction | Egy csoport a További műveletek almenujában, a különálló műveletek után. Egyik alkalmazás sem kap saját bejegyzést az üzenet menüjében. |
registerPostActionComponent | Az üzenet lebegő eszköztáblája, a ⋯ gomb előtt. |
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponent | Az üzenet maga: a teste, a szövege alatt, az idő után, valamint a hivatkozási előnévek helyett. |
registerChannelHeaderMenuAction | A csatorna Csatorna opciók menüje (⋯ egy csatornán az oldalsávban, vagy jobb klikk), dugós ikonú elemként. |
registerMainMenuAction | A közösség menüje (a közösség neve a csatornalista tetején), a További műveletek alatt, alkalmazásonként csoportosítva. |
registerSidebarBrowseOrAddChannelMenuAction | A közösség menüje, a Csatorna létrehozása és a Kategória létrehozása után. |
registerFileUploadMethod | A szerkesztő + menüje (Hozzáadás az üzenethez), a Fájl feltöltése után. |
registerPostEditorActionComponent | A szerkesztő formázósávja, ha a formázás látható. |
registerAIActionMenuItemComponent | A szerkesztő MI menüje. |
registerFileDropdownMenuAction, registerFilePreviewComponent | Egy fájl beállításmenüje, valamint a fájl előnézete. |
registerUserSettings | Profil és beállítások, alkalmazásonként egy-egy fül a Bővítmények fejezet alatt. |
registerChannelSettingsTab | A csatorna beállítások párbeszédablaka, az Alkalmazások fejezet alatt. |
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponent | A profil-kártya, amely akkor jelenik meg, ha egy nevet vagy avartarsatot kattintasz. |
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponent | A közösség csatornalistájának teteje, a csatorna neve és ikonja mellett, valamint a bal oldali közösségi sáv alja. |
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholder | A csatorna előzményeinek kezdete, az üzenetlista teteje, az olvasatlan sor, a szerkesztőmező feletti rész, valamint a szerkesztőmező helyett megjelenő szöveg. |
registerChannelTypeOption | A Csatorna létrehozása párbeszédablak csatornatípusai. |
registerSearchComponents | A csatorna fejlécének keresőmezője: ha üres, akkor az alkalmazáskörzetek jelennek meg benne. |
registerUserGuideDropdownMenuAction | Az Antimatter névjegye (az alkalmazás sávjának alján), a Súgó menü alatt. |
registerProduct | Teljes oldalak a termék URL-címén, amelyek a Termékek alatt szerepelnek az Az Antimatter névjegye menüben. A termékoldalak megtartják a klasszikus oldalkeretet, amelynek termékmenüje csak akkor jelenik meg, ha egy alkalmazás regisztrál egy terméket, vagy hozzáad egy bejegyzést. A csatolt Kanban és Playbook alkalmazások már nem regisztrálnak termékeket: az oldalaik a saját oldalsávjaikban nyílnak meg. |
registerRootComponent, registerGlobalComponent, valamint olyan hookok, mint a registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer és registerTranslations | A klasszikus felülettel megegyező működés. |
registerAdminConsolePlugin, registerAdminConsoleCustomSetting | A Rendszerkonzol, amely mindkét felületen a klasszikus változat. |
Ami a Fusion nem jelenít meg vagy nem futtat
- A
registerPostDropdownMenuComponent(egy komponens az üzenetmenüben), aregisterPostCardTypeComponent(egy bejegyzés kártyája a jobb oldali panelben) és aregisterProductSwitcherMenuItemnem jelennek meg a Fusion fő nézeteiben. Az első helyett használja aregisterPostDropdownMenuActionmetódust. - A
registerMessageWillBeUpdatedHooknem fut le, ha egy üzenetet a Fusionban szerkesztenek. A szerkesztéseket a szerveren aMessageWillBeUpdatedhookkal ellenőrizze. - A
registerActionAfterChannelCreationcsak a klasszikus csatornalétrehozási párbeszédablakból fut le, amelyet a Fusion a Csatorna létrehozása párbeszédablak További beállítások… menüjéből nyit meg. - Az alkalmazás sáv komponensei akkor is megjelennek, ha a
supportedProductIdsértéke bármilyen is. - A
registerNeedsTeamRouteésregisterCustomRouteútvonalai a klasszikus oldalkeretet használják, hasonlóan a termékekhez.
Kizárólag az Antimatterben meglévő hookok
Ezek a regisztrációs metódusok nem léteznek a Mattermostban. Ellenőrizze, hogy a metódus létezik-e, mielőtt meghívná, így az alkalmazás ott is működik:
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');
}
| Metódus | Mit ad hozzá |
|---|---|
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender}) | Egy elem az üzenetmező + menüjében, mindkét felületen. Az action paraméter {channelId, rootId} értéket kap. |
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker}) | Az üzenetmező emoji-választó egy füle, például GIF-ek vagy matricák. A Fusionban a 10-nél kisebb order értékű fülök az Emoji fül előtt jelennek meg. A komponens megkapja a channelId, rootId, filter, onFilterChange, onSelectDone, insertText, isFusion és a Fusionban a pickerKit paramétert (lásd alább). |
registerChannelViewPanel({matcher, component}) | Egy panel a csatorna-fejléc és az üzenetek között, amelyeket a matcher(state, channel) függvény választ ki. Elrejtheti az üzeneteket és a szerkesztőt (setMessagesVisible), ahogy a hangcsatornák teszik. |
registerSidebarChannelFooterComponent(component) | Egy sor a csatorna alatt az oldalsávban, például a csatlakozottak listája egy hívás során. A komponens a channel objektumot kapja. |
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender}) | Csak Fusion: egy bejegyzés az Integrációk oldalon, a saját emoji mellett. A GIFs app a saját GIFjeit és matricáit ide adja hozzá. |
Nézetek hozzáadása és kezelése az emoji-választóban
A Fusionban az emoji-választó fülekhez egy pickerKit prop tartozik: azokat a komponenseket, amelyeket az Emoji-fül a saját hozzáadói és kezelő nézeteihez használ, így a fülek nézetei egységesek maradnak, és a választón belül maradnak. A GIFs és Memes alkalmazások ezzel adják hozzá és kezelik a GIF-eket, matricákat és meme-sablonokat. Tartalmazza a version (1) mezőt, a usePickerView és useOnEscape hookokat, valamint a PickerViewButtons (a keresőmező melletti + és kezelő gombok), PickerViewFrame (a vissza nyilakkal ellátott nézet), PickerNotice, PickerField, PickerSearch, PickerDropZone és PickerManageList komponenseket. A Escape billentyűvel a nézetből a fül rácsnézetére lehet visszatérni. Ellenőrizd, hogy a prop jelen van: más gazdák nem adják meg, és ilyenkor a fül saját párbeszédablakait használja. A típusok a webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) és a komponensek a webapp/fusion/src/fusion/popovers/picker_views.tsx fájlban találhatók.
A panel új ablakban
A Fusion a registerRightHandSidebarComponent komponensét két további prop-pal látja el, hogy a Megnyitás új ablakban opció a panelt ott nyissa meg, ahol éppen volt, nem pedig az alkalmazás főoldalán:
setPanelState(state): akkor hívd meg, ha a panel helye változik, egy rövid, az alkalmazásod által definiált szöveggel, például'note/<id>'vagy'board/<id>/card/<id>', illetvenullértékkel, ha a panel a főoldalon van. Ez az ablak címébe kerül, ezért soha ne helyezz belé titkot. A 512 karaktert meghaladó, vagy vezérlő karaktereket tartalmazó állapot elvetettik.initialPanelState: az új ablakban ez a panel korábbi állapota, vagyundefined. Kezeld mint nem megbízható bemenetet: a bejelentkezett felhasználóként szerezd be újra az elemet, és ha nem nyitható meg, az alkalmazás főoldalát vagy egy „nem található” nézetet jeleníts meg.
Az állapot felejtődik el, ha a panel bezárul, vagy egy másik alkalmazás panelje veszi át a helyét. Ha saját kezdeményezésből nyitod meg a panel ablakát, a popoutRhsPlugin (amely a window.WebappUtils.popouts-ban is elérhető) az állapotot opcionális ötödik argumentumként fogadja el. A Notes, Whiteboard, Todo, Kanban és Playbooks alkalmazások használják ezt.
A fusionIcon a Fusion ikonkészletének egy ikonját nevezi meg (például poll, sticker, calendar vagy image; lásd webapp/fusion/src/fusion/components/icon). A Fusion ezt jeleníti meg a icon helyett, hogy az elem összhangban legyen a többivel.
Beállítások
A plugin.json settings_schema mezője leírja az app oldalát a Rendszerkonzol › Bővítmények alatt:
"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."}
]
}
Beállítás-típusok: bool, text, longtext, number, dropdown, radio, generated (véletlenszerű titok), username és custom (egy komponens által rajzolt, amelyet a webalkalmazás-rész a registerAdminConsoleCustomSetting függvénnyel regisztrál). A beállítások csoportosíthatók sections segítségével.
A szerver-rész ezekbe a struktúrába olvassa be, amelynek mezői a kulcsokkal egyeznek:
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
}
Az adminisztrátorok a konfigurációban is beállíthatják ezeket, a PluginSettings.Plugins.<app id> alatt, kisbetűs kulcsokkal (lásd az adminisztrátori útmutatót).
Fordítások
Az Antimatter 37 nyelvre van fordítva, a csomagolt alkalmazások is. A webalkalmazás-rész így végzi el:
- Minden szöveget React Intl-lel írj meg, azonosítóval és angol szöveggel:
<FormattedMessage id='polls.create' defaultMessage='Create a poll'/>vagydefineMessages. Az azonosítókat az alkalmazás nevével kezdő előtaggal látni el. - Az angol szövegeket a
webapp/i18n/en.jsonfájlba kell kivonni (a csomagolt alkalmazások aformatjs extractparancsot használják). - Minden nyelvhez adj hozzá egy fájlt az en.json mellé, ugyanazokkal az azonosítókkal:
fr.json,de.json,pt-BR.json,zh-CN.json… - Adja át őket a webes alkalmazásnak, amely a felhasználó nyelvét kéri:
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);
Ha egy sztring hiányzik, az angol defaultMessage értékre esik vissza. Azoknál a sztringeknél, amelyeket a szerver rész küld (parancsválaszok, botüzenetek), a pluginapi/i18n csomag betölti a csomagban szállított fordítási fájlokat (például az assets/i18n mappát), és minden felhasználó nyelvét használó lokalizátort ad.
Fordítás, telepítés és hibakeresés
Go és Node.js szükséges (az alkalmazás .nvmrc fájljában megadott verzió). Az alkalmazás mappájában:
| Parancs | Mire szolgál |
|---|---|
make dist | Fordítja a szerver részt minden platformra, valamint a webes alkalmazás részét, és a csomagot a dist/<app id>-<version>.tar.gz fájlba írja. |
make test | Végrehajtja a Go és JavaScript tesztek. |
make check-style | Ellenőrzi a kódot (golangci-lint, ESLint), és ellenőrzi a TypeScript típusokat. |
make deploy | Fordítja, majd telepíti és engedélyezi a csomagot a szerveren. |
make watch, make deploy-from-watch | Az első minden mentéskor újra fordítja a webes alkalmazás részét; a második csomagolja a fordított kódot, és telepíti a szerverre. |
make enable, make disable, make reset | Engedélyezi, letiltja vagy újraindítja az alkalmazást a szerveren. |
make logs, make logs-watch | Megjeleníti a szerver naplófájljában az alkalmazás sorait. |
make attach | Csatlakoztatja a Delve hibakeresőt a futó szerver részhez (előbb fordítsa AM_DEBUG=1 értékkel). |
A make deploy és a többi szerverparancs helyi módban működő szoketot használ, ha talál ilyet (/var/tmp/antimatter_local.socket, vagy AM_LOCALSOCKETPATH): futtassa ezeket a szerver gépén, helyi módban. Egyébként a MM_SERVICESETTINGS_SITEURL által megadott szerverre jelentkeznek be AM_ADMIN_TOKEN, vagy AM_ADMIN_USERNAME és AM_ADMIN_PASSWORD használatával. A fordítóeszközök még nem olvasnak be AM_ nevű változót a szerver URL-jéhez.
Csomag kézi telepítése
- A rendszeradminisztrátor engedélyezi a feltöltést a
AM_PLUGINSETTINGS_ENABLEUPLOADS=truebeállítással (alapértelmezetten kikapcsolva; nincs erre kapcsoló a Rendszerkonzolban). - Ezután Rendszerkonzol › Bővítmények › Bővítmény kezelés › Bővítmény feltöltése, vagy
amctl plugin add weather.tar.gz, majdamctl plugin enable com.example.weather. - Ha a szerveren be van kapcsolva a Bővítmény aláírás szükséges, csak olyan csomagokat fogad el, amelyeket egy megbízható kulccsal aláírtak; lásd Egyéb appok telepítése.
AM_SERVICESETTINGS_ENABLEDEVELOPER=true értéket: ekkor a hibák részletes információt tartalmaznak. A csatolt alkalmazások Makefile-jai csak akkor fordítják a szerver részt a saját platformjára, ha a shell-ben be van állítva a MM_SERVICESETTINGS_ENABLEDEVELOPER.