Menulis aplikasi (plugin)
Aplikasi menambahkan fitur ke Antimatter dari dalam: bagian server dalam Go yang terhubung ke server, dan bagian aplikasi web dalam React yang menambahkan menu, panel, jenis pesan, dan halaman. Halaman ini menunjukkan tata letak aplikasi, menggunakan aplikasi Polls bawaan sebagai contoh, dan apa yang berubah di antarmuka Fusion Antimatter.
Cara kerja aplikasi
- Bagian server adalah program Go. Server menjalankannya sebagai proses terpisah dan berkomunikasi dengannya melalui RPC: server memanggil hook aplikasi (pesan akan diposting, perintah dijalankan…), dan aplikasi memanggil API plugin server (membuat posting, membaca pengguna, menyimpan data…). Aplikasi juga dapat menyajikan rute HTTP di bawah
/plugins/<app id>/. - Bagian aplikasi web adalah bundle JavaScript yang dimuat ke browser bersama aplikasi web. Ini mendaftarkan komponen React dan callback ke registri: tombol di menu, panel, atau cara menggambar jenis pesan.
- Salah satu bagian bersifat opsional. Aplikasi dipasang sebagai bundle
.tar.gz, dan admin sistem mengaktifkan, menonaktifkan, dan mengonfigurasikannya.
Antimatter menjalankan aplikasi yang ditulis untuk Mattermost, dan sebaliknya, selama aplikasi hanya menggunakan hook yang dimiliki keduanya. Lihat Hook yang hanya dimiliki Antimatter.
Tata letak bundle
Tidak ada template starter terpisah: mulai dari aplikasi bawaan kecil seperti antimatter-plugin-polls atau antimatter-plugin-todo, lalu ubah ID dan kodenya. Polls ditata seperti ini:
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
Opsional: folder public/, disajikan apa adanya di /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: unik dan permanen; nama domain terbalik adalah hal yang umum. Ini menamai rute, pengaturan yang disimpan, dan peristiwa WebSocket.version: versi semantik. Aplikasi bawaan tidak menyertakannya diplugin.json; alat pembangunnya mengambilnya dari tag gitv*terbaru.min_server_version: Antimatter melaporkan12.0.0.settings_schema: halaman pengaturan aplikasi di Konsol Sistem (lihat Pengaturan).
make apply menyalin manifest ke server/manifest.go dan webapp/src/manifest.ts; make manifest-check memvalidasinya.
Bagian server
Bagian server mengimpor modul Go yang sama dengan aplikasi Mattermost, github.com/mattermost/mattermost/server/public, dari proxy modul Go. main hanya memulai aplikasi:
package main
import "github.com/mattermost/mattermost/server/public/plugin"
func main() {
plugin.ClientMain(&Plugin{})
}
Jenis Plugin menyematkan plugin.MattermostPlugin, yang memberikannya p.API, dan mengimplementasikan hook yang dibutuhkan:
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)
}
Hook umum
| Hook | Kapan dijalankan |
|---|---|
OnActivate, OnDeactivate | Ketika aplikasi diaktifkan atau dinonaktifkan, dan ketika server dimulai dan dihentikan. Daftarkan perintah dan bot di OnActivate. |
OnConfigurationChange | Ketika pengaturannya berubah; muat dengan p.API.LoadPluginConfiguration(&cfg). |
ServeHTTP | Permintaan ke /plugins/<app id>/…. Server mengatur header Mattermost-User-Id ketika permintaan berasal dari pengguna yang masuk; tolak permintaan tanpa header tersebut kecuali memang dimaksudkan untuk publik. |
ExecuteCommand | Perintah yang didaftarkan oleh aplikasi dijalankan. |
MessageWillBePosted, MessageWillBeUpdated | Sebelum pesan disimpan: kembalikan pesan yang diubah, atau alasan untuk menolaknya. |
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeleted | Setelah kejadian, untuk efek samping. |
ReactionHasBeenAdded, ReactionHasBeenRemoved | Reaksi. |
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreated | Perubahan keanggotaan dan kanal. Tim adalah komunitas. |
FileWillBeUploaded | Sebelum file disimpan: ubah atau tolak. |
OnPluginClusterEvent | Pesan dari aplikasi yang sama di server lain dalam klaster. |
Daftar lengkap, dengan tanda tangan yang tepat, ada di server/public/plugin/hooks.go; API ada di server/public/plugin/api.go. Paket pluginapi (server/public/pluginapi) membungkus API dengan helper yang lebih ramah.
Panggilan API yang berguna
CreatePost,UpdatePost,SendEphemeralPost: kirim sebagai bot aplikasi atau sebagai pengguna.EnsureBotUser(&model.Bot{Username, DisplayName}): buat bot aplikasi sekali dan dapatkan ID-nya.PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): kirim peristiwa ke aplikasi web. Datang sebagaicustom_<app id>_poll_updated.OpenInteractiveDialog: buka dialog.LogInfo,LogErrordan sejenisnya: tulis ke log server, diberi tag dengan ID aplikasi.GetUser,GetChannel,HasPermissionToChannel: periksa siapa yang boleh melakukan apa sebelum bertindak untuk pengguna.
Aplikasi berjalan di setiap server dalam klaster. Simpan status di penyimpanan kunci-nilai atau database, bukan hanya di memori.
Layanan AI
Server Antimatter memanggil model AI untuk aplikasi, melalui koneksi model yang disetel oleh admin (lihat AI di panduan admin). Aplikasi tidak pernah menyimpan kunci penyedia: aplikasi hanya menyebutkan orang yang diwakilinya dan lokasinya, lalu server memeriksa apakah orang tersebut dapat menggunakan koneksi di lokasi itu, menerapkan batas dan anggaran, menghitung token atas nama orang dan aplikasi tersebut, serta mengaudit panggilan tanpa isinya.
| Metode | Fungsinya |
|---|---|
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest) | Penyelesaian percakapan: pesan, alat, keluaran terstruktur (JSONSchema). |
AIChatStream(…) | Sama, tetapi dialirkan: baca Events dari aliran hingga kanal ditutup, atau Close untuk menghentikan panggilan. |
AIEmbed(…, *ai.EmbedRequest) | Embedding teks. |
AITranscribe(…, *ai.TranscribeRequest) | Ucapan ke teks. |
AIDecide(…, *ai.DecideRequest) | Pertanyaan bertipe ke model keputusan (ya atau tidak, pilihan, skor) tentang sebuah teks. |
AIConnectionsForUser(userID, channelID, teamID) | Koneksi yang dapat digunakan seseorang di sana, beserta model dan kemampuannya, bukan kuncinya. |
ConnectionID pada setiap permintaan memilih koneksi, dan Model memilih salah satu modelnya (kosong untuk model bawaan koneksi). Operation adalah label singkat untuk catatan penggunaan dan audit, bukan isinya. Versi server minimumnya adalah 11.11.
actingUserID hanya dari sumber yang telah diverifikasi server: header Mattermost-User-Id pada permintaan ke ServeHTTP Anda, atau pengguna dari konteks hook (pengarang kiriman, pengguna yang menjalankan perintah). Jangan pernah mengambilnya dari pesan, muatan webhook, URL, atau permintaan aplikasi lain: aplikasi Anda akan menghabiskan akses orang lain.Metode-metode ini dan paket ai (server/public/ai) hanya ada pada salinan modul milik Antimatter, bukan pada versi yang diterbitkan oleh Mattermost. Untuk menggunakannya, bangun modul terhadap server/public Antimatter dengan baris replace di go.mod Anda, misalnya replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public. Aplikasi semacam ini hanya berjalan di Antimatter.
Menyimpan data
Setiap aplikasi memiliki penyimpanan kunci-nilai sendiri di database server:
KVSet(key, value),KVGet(key),KVDelete(key): nilai berupa byte, biasanya JSON. Kunci maksimal 150 karakter.KVSetWithExpiry(key, value, seconds): nilai akan hilang setelah waktu tersebut.KVCompareAndSet(key, old, new)danKVSetWithOptionsdenganAtomic: pembaruan aman ketika beberapa permintaan atau server menulis kunci yang sama. Polls menyimpan setiap suara dengan cara ini dan mengulang saat terjadi konflik.KVList(page, perPage): kunci, per halaman.
Bagian aplikasi web
Bundel mendaftarkan kelas dengan window.registerPlugin. Metode initialize menerima registri dan store Redux:
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());
- Perpustakaan bersama. Aplikasi web menyediakan React, ReactDOM, Redux, React Redux, dan React Intl: cantumkan sebagai
externalswebpack (React,ReactDOM,Redux,ReactRedux,ReactIntl) alih-alih membundel salinan Anda sendiri. Lihatwebpack.config.jsPolls. - Memanggil bagian server Anda. Ambil
${window.basename}/plugins/<app id>/…dengan opsi dariClient4.getOptions()(darimattermost-redux/client): opsi ini membawa header yang diperlukan server untuk menerima permintaan dari browser. - Status Anda sendiri.
registerReducermenambahkan reducer, yang disimpan di bawahstate['plugins-<app id>']. - Tipe. Metode registri tambahan Antimatter tidak ada dalam tipe yang dipublikasikan Mattermost: Polls mendeklarasikan registri yang digunakan di
webapp/src/types/host.ts.
Metode registri dan parameternya didokumentasikan dalam kode, di webapp/fusion/src/plugins/registry.ts (Fusion) dan webapp/channels/src/plugins/registry.ts (klasik).
Mendukung antarmuka Fusion
Antimatter memiliki dua antarmuka web: Fusion (standar) dan klasik. Keduanya memuat bundel aplikasi yang sama dan memiliki registri yang sama, tetapi Fusion menggambar banyak hal sendiri dan menempatkan komponen plugin dengan caranya sendiri. Uji aplikasi Anda di keduanya.
Mendeteksi antarmuka
Sebelum aplikasi dimuat, kedua antarmuka mengatur window.antimatterWebUI menjadi 'fusion' atau 'classic', dan nilai yang sama pada elemen akar halaman sebagai data-am-web-ui. Di Mattermost, keduanya tidak diatur.
export function isFusionUI(): boolean {
return window.antimatterWebUI === 'fusion' || document.documentElement.dataset.amWebUi === 'fusion';
}
Aplikasi bawaan menggunakan ini untuk menggambar antarmuka dengan cara yang berbeda. Poll menggambar kartu jajak pendapat dan dialog pembuatannya dengan gaya Fusion, dan membuka dialognya sendiri untuk /poll di Fusion. Calls dan Kanal Suara tidak menyertakan komponen bilah samping dan toast yang diganti Fusion dengan antarmuka panggilannya sendiri. Aplikasi Agen menempatkan aksi AI-nya di menu pesan, sebagai grup di bawah Lainnya, bukan di bilah alat hover. Kelas CSS Fusion (dengan awalan am-) dan lapisan dialognya (elemen am-layer) adalah yang digunakan aplikasi-aplikasi ini untuk menyelaraskan antarmuka; ini bukan API yang didokumentasikan dan stabil.
Di mana Fusion menampilkan komponen plugin
| Metode registri | Di mana muncul di Fusion |
|---|---|
registerAppBarComponent, registerChannelHeaderButtonAction | Rel aplikasi, kolom ikon di tepi kanan, antara avatar Anda dan tombol Tentang Antimatter. Tombol header kanal juga berada di sana, bukan di header kanal. Disembunyikan ketika admin sistem mengaktifkan Nonaktifkan Bilah Aplikasi (ExperimentalSettings.DisableAppBar, nonaktif secara default). |
registerRightHandSidebarComponent | Panel di sisi kanan. Orang dapat mengubah ukurannya dengan menyeret tepinya, dan membukanya di jendela baru. Jika aplikasi tersebut juga merupakan produk, panel menawarkan Buka sebagai halaman penuh. Lihat Panel di jendela baru. |
registerChannelHeaderIcon | Ikon di header kanal, setelah tombol panggilan; di ponsel, di menu Lainnya header. |
registerCallButtonAction | Tombol panggilan di header kanal; beberapa penyedia berbagi menu Cara lain untuk melakukan panggilan. |
registerPostDropdownMenuAction | Menu Aksi pesan (⋯) pesan, di submenu Lainnya; juga di menu Tindakan utas panel utas, di bawah Lainnya. Fusion menggambar ikon aplikasi di depan setiap aksi, berwarna abu-abu: ikonnya sendiri untuk aplikasi bawaan, jika tidak, ikon yang ditampilkan aplikasi di rel aplikasi, jika tidak, ikon netral. Elemen tanpa teks di awal teks aksi (ikon yang digambar oleh aplikasi itu sendiri) disembunyikan. |
registerPostDropdownSubMenuAction | Grup dengan judul di submenu Lainnya yang sama, setelah aksi tunggal. Tidak ada aplikasi yang mendapatkan entri miliknya sendiri di menu pesan. |
registerPostActionComponent | Bilah alat hover pesan, sebelum tombol ⋯. |
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponent | Pesan itu sendiri: isinya, di bawah teksnya, setelah waktunya, dan menggantikan pratinjau tautan. |
registerChannelHeaderMenuAction | Menu Opsi kanal kanal (⋯ pada kanal di bilah samping, atau klik kanan), sebagai item dengan ikon colokan. |
registerMainMenuAction | Menu komunitas (nama komunitas di bagian atas daftar kanal), di bawah Lainnya, dikelompokkan per aplikasi. |
registerSidebarBrowseOrAddChannelMenuAction | Menu komunitas, setelah Buat kanal dan Buat kategori. |
registerFileUploadMethod | Menu + komposer (Tambahkan ke pesan), setelah Unggah file. |
registerPostEditorActionComponent | Bilah format komposer, ketika format ditampilkan. |
registerAIActionMenuItemComponent | Menu AI komposer. |
registerFileDropdownMenuAction, registerFilePreviewComponent | Menu opsi file, dan pratinjau file. |
registerUserSettings | Profil & pengaturan, satu tab per aplikasi di bawah judul Plugin. |
registerChannelSettingsTab | Dialog pengaturan kanal, di bawah judul Aplikasi. |
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponent | Kartu profil yang ditampilkan ketika Anda mengklik nama atau avatar. |
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponent | Bagian atas daftar kanal komunitas, di samping nama kanal, ikon kanal, dan bagian bawah bilah komunitas di sisi kiri. |
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholder | Awal riwayat kanal, bagian atas daftar pesan, garis belum dibaca, di atas komposer, dan placeholder komposer. |
registerChannelTypeOption | Jenis kanal dalam dialog Buat kanal. |
registerSearchComponents | Kotak cari di header kanal: cakupan aplikasi muncul saat kotak kosong. |
registerUserGuideDropdownMenuAction | Tentang Antimatter (bagian bawah bilah aplikasi), di bawah Bantuan. |
registerProduct | Halaman penuh di URL produk, yang terdaftar di bawah Produk di Tentang Antimatter. Halaman produk mempertahankan bingkai halaman klasik, di mana menu produk hanya muncul ketika aplikasi mendaftarkan produk atau menambahkan entri ke dalamnya. Aplikasi Kanban dan Playbooks bawaan tidak lagi mendaftarkan produk: halaman mereka terbuka di panel samping mereka. |
registerRootComponent, registerGlobalComponent, hook seperti registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer, registerTranslations | Berfungsi seperti pada antarmuka klasik. |
registerAdminConsolePlugin, registerAdminConsoleCustomSetting | Konsol Sistem, yang merupakan versi klasik di kedua antarmuka. |
Yang tidak ditampilkan atau dijalankan oleh Fusion
registerPostDropdownMenuComponent(komponen di menu pesan),registerPostCardTypeComponent(kartu pesan di panel kanan) danregisterProductSwitcherMenuItemtidak ditampilkan di tampilan utama Fusion. GunakanregisterPostDropdownMenuActionsebagai pengganti yang pertama.registerMessageWillBeUpdatedHooktidak dijalankan saat pesan diedit di Fusion. Periksa pengeditan di server dengan hookMessageWillBeUpdatedsebagai gantinya.registerActionAfterChannelCreationhanya dijalankan dari dialog pembuatan kanal klasik, yang Fusion buka dari Opsi lainnya… di dialog Buat kanal-nya.- Komponen bilah aplikasi ditampilkan apa pun nilai
supportedProductIds-nya. - Rute dari
registerNeedsTeamRoutedanregisterCustomRoutemempertahankan bingkai halaman klasik, seperti produk.
Hook yang hanya dimiliki Antimatter
Metode registry ini tidak ada di Mattermost. Periksa apakah metode tersebut ada sebelum memanggilnya, agar aplikasi juga berfungsi di sana:
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');
}
| Metode | Yang ditambahkan |
|---|---|
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender}) | Item di menu + kotak pesan, di kedua antarmuka. action menerima {channelId, rootId}. |
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker}) | Tab dari pemilih emoji kotak pesan, seperti GIF atau stiker. Di Fusion, tab dengan order di bawah 10 muncul sebelum tab Emoji. Komponen menerima channelId, rootId, filter, onFilterChange, onSelectDone, insertText, isFusion dan, di Fusion, pickerKit (lihat di bawah). |
registerChannelViewPanel({matcher, component}) | Panel di antara header kanal dan pesan, untuk kanal yang dipilih oleh matcher(state, channel). Panel ini dapat menyembunyikan pesan dan komposer (setMessagesVisible), seperti yang dilakukan oleh kanal suara. |
registerSidebarChannelFooterComponent(component) | Baris di bawah sebuah kanal di bilah samping, seperti orang-orang yang sedang dalam panggilannya. Baris ini menerima channel. |
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender}) | Khusus Fusion: entri di halaman Integrasi, di sebelah emoji kustom. Aplikasi GIF menambahkan GIF dan stiker kustomnya di sana. |
Menambahkan dan mengelola tampilan di pemilih emoji
Di Fusion, tab pemilih emoji memiliki prop pickerKit: komponen yang digunakan tab Emoji untuk tampilan tambah dan kelolanya sendiri, sehingga tampilan tab terlihat seragam dan tetap berada di dalam pemilih. Aplikasi GIF dan Meme menggunakannya untuk menambah dan mengelola GIF, stiker, dan template meme. Prop ini berisi version (1), hook usePickerView dan useOnEscape, serta komponen PickerViewButtons (tombol + dan kelola di samping kotak pencarian), PickerViewFrame (tampilan dengan panah kembali), PickerNotice, PickerField, PickerSearch, PickerDropZone, dan PickerManageList. Tekan Escape untuk kembali dari tampilan ke grid tab. Pastikan prop ini ada: host lain tidak menyediakannya, dan tab akan menggunakan dialognya sendiri. Tipe data ada di webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) dan komponen ada di webapp/fusion/src/fusion/popovers/picker_views.tsx.
Panel di jendela baru
Fusion memberikan dua prop tambahan ke komponen registerRightHandSidebarComponent, sehingga Buka di jendela baru membuka panel di tempat asalnya, bukan di beranda aplikasi:
setPanelState(state): panggil ini ketika panel berpindah tempat, dengan string pendek yang didefinisikan oleh aplikasi Anda, seperti'note/<id>'atau'board/<id>/card/<id>', ataunulldi beranda. Nilai ini masuk ke alamat jendela, jadi jangan pernah menyimpan rahasia di dalamnya. State yang lebih dari 512 karakter, atau mengandung karakter kontrol, akan diabaikan.initialPanelState: di jendela baru, ini adalah state yang dimiliki panel, atauundefined. Perlakukan sebagai input yang tidak dapat dipercaya: ambil ulang item sebagai pengguna yang sedang masuk, dan tampilkan beranda aplikasi atau tampilan tidak ditemukan jika mereka tidak dapat membukanya.
State dilupakan ketika panel ditutup atau panel aplikasi lain mengambil tempatnya. Untuk membuka jendela panel secara mandiri, popoutRhsPlugin (juga ada di window.WebappUtils.popouts) menerima state sebagai argumen kelima opsional. Catatan, Papan Putih, To-do, Kanban, dan Buku Taktik menggunakan ini.
fusionIcon menentukan nama ikon dari set ikon Fusion (misalnya poll, sticker, calendar, atau image; lihat webapp/fusion/src/fusion/components/icon). Fusion menampilkan ikon ini alih-alih icon, sehingga item tersebut sesuai dengan item lainnya.
Pengaturan
settings_schema di plugin.json mendeskripsikan halaman aplikasi di Konsol Sistem › Plugin:
"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."}
]
}
Jenis pengaturan: bool, text, longtext, number, dropdown, radio, generated (rahasia acak), username, dan custom (digambar oleh komponen yang didaftarkan oleh bagian web app dengan registerAdminConsoleCustomSetting). Pengaturan dapat dikelompokkan dalam sections.
Bagian server membacanya ke dalam struktur data (struct) yang field-nya sesuai dengan kuncinya:
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
}
Admin juga dapat menyetelnya dalam konfigurasi, di bawah PluginSettings.Plugins.<app id>, dengan kunci dalam huruf kecil (lihat panduan admin).
Terjemahan
Antimatter diterjemahkan ke dalam 37 bahasa, dan aplikasi bawaan juga demikian. Bagian web app melakukannya seperti ini:
- Tulis setiap string dengan React Intl, dengan ID dan teks bahasa Inggrisnya:
<FormattedMessage id='polls.create' defaultMessage='Create a poll'/>ataudefineMessages. Beri awalan ID dengan nama aplikasi Anda. - Ekstrak string bahasa Inggris ke
webapp/i18n/en.json(aplikasi bawaan menggunakanformatjs extract). - Tambahkan satu file per bahasa di sebelahnya, dengan ID yang sama:
fr.json,de.json,pt-BR.json,zh-CN.json… - Berikan kepada aplikasi web, yang meminta bahasa pengguna:
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);
String yang hilang akan kembali ke defaultMessage berbahasa Inggris. Untuk string yang dikirim oleh bagian server (jawaban perintah, pesan bot), paket pluginapi/i18n memuat file terjemahan yang disertakan dalam bundle (misalnya assets/i18n) dan memberikan lokalizer dalam bahasa masing-masing pengguna.
Membangun, menginstal, dan men-debug
Anda membutuhkan Go dan Node.js (versi yang ada di .nvmrc aplikasi). Di folder aplikasi:
| Perintah | Fungsinya |
|---|---|
make dist | Membangun bagian server untuk semua platform dan bagian aplikasi web, lalu menulis bundle ke dist/<app id>-<version>.tar.gz. |
make test | Menjalankan tes Go dan JavaScript. |
make check-style | Melint kode (golangci-lint, ESLint) dan memeriksa tipe TypeScript. |
make deploy | Membangun, lalu menginstal dan mengaktifkan bundle di server. |
make watch, make deploy-from-watch | Yang pertama membangun ulang bagian aplikasi web setiap kali Anda menyimpan; yang kedua membundel apa yang dibangun dan menginstalnya di server. |
make enable, make disable, make reset | Mengaktifkan, menonaktifkan, atau memulai ulang aplikasi di server. |
make logs, make logs-watch | Menampilkan baris aplikasi di log server. |
make attach | Menempelkan debugger Delve ke bagian server yang sedang berjalan (bangun dengan AM_DEBUG=1 terlebih dahulu). |
make deploy dan perintah server lainnya menggunakan soket mode lokal jika menemukannya (/var/tmp/antimatter_local.socket, atau AM_LOCALSOCKETPATH): jalankan di mesin server dengan mode lokal aktif. Jika tidak, mereka masuk ke server yang diberikan oleh MM_SERVICESETTINGS_SITEURL dengan AM_ADMIN_TOKEN, atau AM_ADMIN_USERNAME dan AM_ADMIN_PASSWORD. Alat build belum membaca nama AM_ untuk URL situs.
Menginstal bundle secara manual
- Admin sistem mengizinkan unggahan dengan
AM_PLUGINSETTINGS_ENABLEUPLOADS=true(nonaktif secara default; tidak ada sakelar di Konsol Sistem). - Lalu Konsol Sistem › Plugin › Manajemen Plugin › Unggah Plugin, atau
amctl plugin add weather.tar.gzdiikuti denganamctl plugin enable com.example.weather. - Jika server memiliki Wajibkan Tanda Tangan Plugin aktif, ia hanya menerima bundle yang ditandatangani dengan kunci yang dipercaya; lihat Menginstal aplikasi lain.
AM_SERVICESETTINGS_ENABLEDEVELOPER=true di server: kesalahan kemudian membawa detailnya. Makefile aplikasi terbundle membangun bagian server hanya untuk platform Anda ketika MM_SERVICESETTINGS_ENABLEDEVELOPER disetel di shell Anda.