Menulis aplikasi (plug-in)

Aplikasi menambah ciri ke dalam Antimatter: bahagian pelayan dalam Go yang disambungkan ke pelayan, dan bahagian aplikasi web dalam React yang menambah menu, panel, jenis mesej dan halaman. Halaman ini menunjukkan susunan aplikasi, menggunakan aplikasi Undian yang dibundel sebagai contoh, dan apa yang berubah dalam antara muka Fusion Antimatter.

Cara aplikasi berfungsi

  • Bahagian pelayan ialah program Go. Pelayan memulakannya sebagai proses berasingan dan berinteraksi dengannya melalui RPC: ia memanggil hook aplikasi (mesej akan diposkan, arahan dijalankan…), dan aplikasi memanggil API plug-in pelayan (mencipta pos, membaca pengguna, menyimpan data…). Ia juga boleh menyediakan laluan HTTP di bawah /plugins/<app id>/.
  • Bahagian aplikasi web ialah bundle JavaScript yang dimuat ke pelayar bersama aplikasi web. Ia mendaftarkan komponen React dan callback dengan registri: butang dalam menu, panel, cara untuk melukis jenis mesej.
  • Mana-mana bahagian adalah pilihan. Aplikasi dipasang sebagai bundle .tar.gz, dan pentadbir sistem membolehkan, melumpuhkan dan mengkonfigurasikannya.
Bahagian pelayan berjalan dengan akses penuh ke data pelayan. Rawat aplikasi seperti kod yang anda deploy ke pelayan.

Antimatter menjalankan aplikasi yang ditulis untuk Mattermost, dan sebaliknya, selagi aplikasi hanya menggunakan hook yang dimiliki oleh kedua-duanya. Lihat Hook yang hanya dimiliki oleh Antimatter.

Susunan bundle

Tiada templat pemula berasingan: mulakan daripada aplikasi bundel kecil seperti antimatter-plugin-polls atau antimatter-plugin-todo, dan ubah ID serta kodnya. Undian disusun 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

Pilihan: folder public/, dilayani seperti 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 kekal; nama domain terbalik adalah biasa. Ia menamakan laluan, tetapan yang disimpan dan peristiwa WebSocket.
  • version: versi semantik. Aplikasi bundel tidak menyertainya dalam plugin.json; alat pembinaannya mengambilnya daripada tag git v* terkini.
  • min_server_version: Antimatter melaporkan 12.0.0.
  • settings_schema: halaman tetapan aplikasi dalam Konsol Sistem (lihat Tetapan).

make apply menyalin manifest ke server/manifest.go dan webapp/src/manifest.ts; make manifest-check memvalidasinya.

Bahagian pelayan

Bahagian pelayan mengimport modul Go yang sama seperti aplikasi Mattermost, github.com/mattermost/mattermost/server/public, dari proksi modul Go. main miliknya hanya memulakan aplikasi:

package main

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

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

Jenis Plugin membenamkan plugin.MattermostPlugin, yang memberikannya p.API, dan melaksanakan hook yang diperlukan:

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 biasa

HookBila ia dilaksanakan
OnActivate, OnDeactivateBila aplikasi diaktifkan atau dinyahaktifkan, dan bila pelayan bermula dan berhenti. Daftarkan arahan dan bot dalam OnActivate.
OnConfigurationChangeBila tetapan berubah; muatkannya dengan p.API.LoadPluginConfiguration(&cfg).
ServeHTTPPermintaan ke /plugins/<app id>/…. Pelayan menetapkan pengepala Mattermost-User-Id bila permintaan datang daripada pengguna yang log masuk; tolak permintaan tanpa pengepala ini melainkan ia dimaksudkan untuk awam.
ExecuteCommandArahan yang didaftarkan oleh aplikasi telah dilaksanakan.
MessageWillBePosted, MessageWillBeUpdatedSebelum mesej disimpan: kembalikan hantaran yang diubah, atau sebab untuk menolaknya.
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeletedSelepas kejadian, untuk kesan sampingan.
ReactionHasBeenAdded, ReactionHasBeenRemovedReaksi.
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreatedKeahlian dan perubahan saluran. Pasukan ialah komuniti.
FileWillBeUploadedSebelum fail disimpan: ubah atau tolak.
OnPluginClusterEventMesej daripada aplikasi yang sama pada pelayan lain dalam kluster.

Senarai penuh, dengan tanda tangan yang tepat, ada dalam server/public/plugin/hooks.go; API ada dalam server/public/plugin/api.go. Pakej pluginapi (server/public/pluginapi) membungkus API dalam pembantu yang lebih mesra.

Panggilan API berguna

  • CreatePost, UpdatePost, SendEphemeralPost: hantar sebagai bot aplikasi atau sebagai pengguna.
  • EnsureBotUser(&model.Bot{Username, DisplayName}): cipta bot aplikasi sekali dan dapatkan ID-nya.
  • PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): hantar peristiwa ke aplikasi web. Ia tiba sebagai custom_<app id>_poll_updated.
  • OpenInteractiveDialog: buka dialog.
  • LogInfo, LogError dan rakan-rakan: tulis ke log pelayan, ditanda dengan ID aplikasi.
  • GetUser, GetChannel, HasPermissionToChannel: semak siapa yang boleh melakukan apa sebelum bertindak untuk pengguna.

Aplikasi ini berjalan pada setiap pelayan dalam kluster. Simpan keadaan dalam stor kunci-nilai atau pangkalan data, bukan hanya dalam memori.

Perkhidmatan AI

Pelayan Antimatter memanggil model AI untuk aplikasi, melalui sambungan model yang diset oleh pentadbir (lihat AI dalam panduan pentadbiran). Aplikasi tidak pernah memegang kunci penderma: ia hanya menyatakan nama individu yang dilayan dan lokasinya, dan pelayan akan memeriksa sama ada individu tersebut dibenarkan menggunakan sambungan di situ, mengenakan had dan belanjanya, mengira token terhadap individu dan aplikasi tersebut, serta mengaudit panggilan tanpa mengandungi isinya.

KaedahFungsinya
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest)Penyempurnaan sembang: mesej, alat, keluaran berstruktur (JSONSchema).
AIChatStream(…)Sama, tetapi dalam aliran: baca Events aliran sehingga saluran ditutup, atau Close untuk menghentikan panggilan.
AIEmbed(…, *ai.EmbedRequest)Penyematan teks.
AITranscribe(…, *ai.TranscribeRequest)Suara ke teks.
AIDecide(…, *ai.DecideRequest)Soalan bertip kepada model keputusan (ya atau tidak, pilihan, skor) tentang sesuatu teks.
AIConnectionsForUser(userID, channelID, teamID)Sambungan yang boleh digunakan oleh seseorang di situ, dengan model dan keupayaannya, tetapi tidak pernah kuncinya.

ConnectionID bagi setiap permintaan memilih sambungan, dan Model memilih salah satu modelnya (kosong untuk lalai sambungan). Operation ialah label ringkas untuk rekod penggunaan dan audit, bukan isinya. Versi pelayan minimumnya ialah 11.11.

Ambil actingUserID hanya daripada sumber yang disahkan oleh pelayan: pengepala Mattermost-User-Id bagi permintaan kepada ServeHTTP anda, atau pengguna dalam konteks hook (pengarang hantaran, pengguna yang menjalankan arahan). Jangan pernah ambillah daripada mesej, muatan webhook, URL atau permintaan aplikasi lain: aplikasi anda akan menggunakan akses orang lain.

Kaedah ini dan pakej ai (server/public/ai) wujud hanya dalam salinan modul Antimatter, bukan dalam versi yang diterbitkan oleh Mattermost. Untuk menggunakannya, bina terhadap server/public Antimatter dengan baris replace dalam go.mod anda, sebagai contoh replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public. Aplikasi sedemikian hanya akan berjalan di Antimatter.

Menyimpan data

Setiap aplikasi mempunyai stor kunci-nilai miliknya sendiri dalam pangkalan data pelayan:

  • KVSet(key, value), KVGet(key), KVDelete(key): nilai adalah dalam bentuk pita (bytes), biasanya JSON. Kunci adalah paling banyak 150 aksara.
  • KVSetWithExpiry(key, value, seconds): nilai akan hilang selepas tempoh masa tersebut.
  • KVCompareAndSet(key, old, new) dan KVSetWithOptions dengan Atomic: kemas kini yang selamat apabila beberapa permintaan atau pelayan menulis ke kunci yang sama. Undian menyimpan setiap undian dengan cara ini dan mencuba semula jika berlaku percanggahan.
  • KVList(page, perPage): kunci, halaman demi halaman.

Bahagian aplikasi web

Bundel (bundle) mendaftar kelas dengan window.registerPlugin. Metod initialize miliknya menerima registri dan stor 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());
  • Pustaka bersama. Aplikasi web menyediakan React, ReactDOM, Redux, React Redux dan React Intl: senaraikan sebagai externals webpack (React, ReactDOM, Redux, ReactRedux, ReactIntl) bukannya membundel salinan anda sendiri. Lihat webpack.config.js Undian.
  • Memanggil bahagian pelayan anda. Ambil (fetch) ${window.basename}/plugins/<app id>/… dengan pilihan daripada Client4.getOptions() (daripada mattermost-redux/client): ia membawa pengepala (headers) yang diperlukan oleh pelayan untuk menerima permintaan daripada pelayar.
  • Keadaan anda sendiri. registerReducer menambah reducer, disimpan di bawah state['plugins-<app id>'].
  • Jenis (Types). Kaedah registri tambahan Antimatter tidak terdapat dalam jenis yang diterbitkan oleh Mattermost: Undian menyatakan registri yang digunakan dalam webapp/src/types/host.ts.

Kaedah registri dan parameternya didokumentasikan dalam kod, dalam webapp/fusion/src/plugins/registry.ts (Fusion) dan webapp/channels/src/plugins/registry.ts (klasik).

Menyokong antara muka Fusion

Antimatter mempunyai dua antara muka web: Fusion, yang lalai, dan yang klasik. Kedua-duanya memuatkan bundel aplikasi yang sama dan mempunyai registri yang sama, tetapi Fusion melukis banyak perkara sendiri dan meletakkan komponen plugin dengan caranya sendiri. Ujikan aplikasi anda dalam kedua-duanya.

Mengesan antara muka

Sebelum mana-mana aplikasi dimuatkan, kedua-dua antara muka menetapkan window.antimatterWebUI kepada 'fusion' atau 'classic', dan nilai yang sama pada elemen akar halaman sebagai data-am-web-ui. Pada Mattermost, tiada satu pun ditetapkan.

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

Aplikasi terikat menggunakan ini untuk melukis dengan cara yang berbeza. Undian melukis kad undian dan dialog penciptaannya dalam gaya Fusion, dan membuka dialognya sendiri untuk /poll dalam Fusion. Panggilan dan Saluran Suara meninggalkan komponen bar sisi dan toast yang digantikan oleh Fusion dengan antara muka panggilannya sendiri. Aplikasi Ejen meletakkan tindakan AI-nya dalam menu mesej, sebagai kumpulan di bawah Lagi Tindakan, bukannya bar alat hover. Kelas CSS Fusion sendiri (dihubungkan dengan am-) dan lapisan dialognya (elemen am-layer) adalah apa yang digunakan oleh aplikasi ini untuk memadankan antara muka; ia bukan API yang didokumentasikan dan stabil.

Di mana Fusion menunjukkan komponen plugin

Kaedah registriDi mana ia muncul dalam Fusion
registerAppBarComponent, registerChannelHeaderButtonActionRel aplikasi, lajur ikon di hujung kanan, antara avatar anda dan butang Tentang Antimatter. Butang pengepal saluran juga pergi ke sana, bukan dalam pengepal saluran. Disembunyikan apabila pentadbir sistem menghidupkan Matikan Bar Aplikasi (ExperimentalSettings.DisableAppBar, luar secara lalai).
registerRightHandSidebarComponentPanel sebelah kanan. Orang boleh mengubah saiznya dengan menarik tepinya, dan membukanya dalam tetingkap baharu. Jika aplikasi itu juga merupakan produk, panel menawarkan Buka sebagai halaman penuh. Lihat Panel dalam tetingkap baharu.
registerChannelHeaderIconIkon dalam pengepal saluran, selepas butang panggilan; pada telefon, dalam menu Lagi pengepal.
registerCallButtonActionButang panggilan pengepal saluran; beberapa penyedia berkongsi menu Cara lain untuk membuat panggilan.
registerPostDropdownMenuActionMenu Aksi mesej (⋯) mesej, dalam submenunya Lagi Tindakan; juga dalam menu Tindakan bebenang panel bebenang, di bawah Lagi Tindakan. Fusion melukis ikon aplikasi sebelum setiap tindakan, dalam kelabu: ikonnya sendiri untuk aplikasi terikat, jika tidak ikon yang dipaparkan oleh aplikasi dalam rel aplikasi, jika tidak yang neutral. Elemen tanpa teks di awal teks tindakan (ikon yang dilukis oleh aplikasi itu sendiri) disembunyikan.
registerPostDropdownSubMenuActionKumpulan dengan tajuk dalam submenunya Lagi Tindakan yang sama, selepas tindakan tunggal. Tiada aplikasi mendapat entri miliknya sendiri dalam menu mesej.
registerPostActionComponentBar alat hover mesej, sebelum butang ⋯.
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponentMesej itu sendiri: badannya, di bawah teksnya, selepas masanya, dan di tempat pratonton pautan.
registerChannelHeaderMenuActionMenu Pilihan saluran saluran (⋯ pada saluran dalam bar sisi, atau klik kanan), sebagai item dengan ikon palam.
registerMainMenuActionMenu komuniti (nama komuniti di bahagian atas senarai saluran), di bawah Lagi Tindakan, dikelompokkan mengikut aplikasi.
registerSidebarBrowseOrAddChannelMenuActionMenu komuniti, selepas Cipta saluran dan Cipta kategori.
registerFileUploadMethodMenu + komposer (Tambah pada mesej), selepas Muat naik fail.
registerPostEditorActionComponentBar format komposer, apabila format dipaparkan.
registerAIActionMenuItemComponentMenu AI komposer.
registerFileDropdownMenuAction, registerFilePreviewComponentMenu pilihan fail, dan pratonton fail.
registerUserSettingsProfil & tetapan, satu tab setiap aplikasi di bawah tajuk Plugin.
registerChannelSettingsTabDialog tetapan saluran, di bawah tajuk Aplikasi.
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponentKad profil yang dipaparkan apabila anda mengklik nama atau avatar.
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponentBahagian atas senarai saluran komuniti, di sebelah nama saluran, ikon saluran, dan bahagian bawah rel komuniti di sebelah kiri.
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholderMula-mula sejarah saluran, bahagian atas senarai mesej, garisan belum dibaca, di atas komposer, dan pemegang tempat komposer.
registerChannelTypeOptionJenis-jenis saluran dalam dialog Cipta saluran.
registerSearchComponentsKotak carian dalam pengepal saluran: skop aplikasi muncul apabila ia kosong.
registerUserGuideDropdownMenuActionTentang Antimatter (bahagian bawah rel aplikasi), di bawah Bantuan.
registerProductHalaman penuh pada URL produk, disenaraikan di bawah Produk dalam Tentang Antimatter. Halaman produk mengekalkan bingkai halaman klasik, yang menu produknya hanya dipaparkan apabila aplikasi mendaftar produk atau menambah entri ke dalamnya. Aplikasi Kanban dan Buku Taktik terikat tidak lagi mendaftar produk: halaman mereka dibuka dalam panel sisi mereka.
registerRootComponent, registerGlobalComponent, hook seperti registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer, registerTranslationsBerfungsi seperti dalam antara muka klasik.
registerAdminConsolePlugin, registerAdminConsoleCustomSettingKonsol Sistem, yang merupakan versi klasik dalam kedua-dua antara muka.

Apa yang tidak dipaparkan atau dijalankan oleh Fusion

  • registerPostDropdownMenuComponent (komponen dalam menu mesej), registerPostCardTypeComponent (kad mesej dalam panel kanan) dan registerProductSwitcherMenuItem tidak dipaparkan dalam pandangan utama Fusion. Guna registerPostDropdownMenuAction sebagai ganti yang pertama.
  • registerMessageWillBeUpdatedHook tidak dijalankan apabila mesej disunting dalam Fusion. Periksa pindaan pada pelayan dengan hook MessageWillBeUpdated sebagai gantinya.
  • registerActionAfterChannelCreation hanya dijalankan dari dialog penciptaan saluran klasik, yang dibuka oleh Fusion dari Pilihan lain… dalam dialog Cipta salurannya.
  • Komponen bar aplikasi dipaparkan tanpa mengira supportedProductIds mereka.
  • Laluan dari registerNeedsTeamRoute dan registerCustomRoute mengekalkan bingkai laman klasik, seperti produk.

Hook yang hanya ada pada Antimatter

Kaedah registri ini tidak wujud pada Mattermost. Pastikan kaedah wujud sebelum dipanggil, supaya 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');
}
KaedahApa yang ditambah
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender})Item dalam menu + kotak mesej, dalam kedua-dua antara muka. action menerima {channelId, rootId}.
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker})Tab pemilih emoji kotak mesej, seperti GIF atau pelekat. Dalam Fusion, tab dengan order di bawah 10 datang sebelum tab Emoji. Komponen menerima channelId, rootId, filter, onFilterChange, onSelectDone, insertText, isFusion dan, dalam Fusion, pickerKit (lihat di bawah).
registerChannelViewPanel({matcher, component})Panel antara pengepala saluran dan mesej, untuk saluran yang dipilih oleh matcher(state, channel). Ia boleh menyembunyikan mesej dan komposer (setMessagesVisible), seperti yang dilakukan oleh saluran suara.
registerSidebarChannelFooterComponent(component)Baris di bawah saluran dalam bar sisi, seperti orang-orang dalam panggilannya. Ia menerima channel.
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender})Khusus Fusion: entri pada halaman Integrasi, bersebelahan emoji tersuai. Aplikasi GIF menambah GIF dan pelekat tersuainya di sana.

Tambah dan urus paparan dalam pemilih emoji

Dalam Fusion, tab pemilih emoji menerima prop pickerKit: komponen yang digunakan oleh tab Emoji untuk paparan tambah dan urusannya sendiri, supaya paparan tab kelihatan sama dan kekal di dalam pemilih. Aplikasi GIF dan Memes menggunakannya untuk menambah dan mengurus GIF, pelekat dan templat meme. Ia mengandungi version (1), hook usePickerView dan useOnEscape, serta komponen PickerViewButtons (butang + dan urus di sebelah kotak carian), PickerViewFrame (paparan dengan anak panah belakang), PickerNotice, PickerField, PickerSearch, PickerDropZone dan PickerManageList. Tekan Escape untuk kembali dari paparan ke grid tab. Semak bahawa prop ini wujud: hos lain tidak menyertainya, dan tab akan mengekalkan dialognya sendiri. Jenisnya terdapat dalam webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) dan komponennya dalam webapp/fusion/src/fusion/popovers/picker_views.tsx.

Panel dalam tetingkap baharu

Fusion memberikan dua prop tambahan kepada komponen registerRightHandSidebarComponent, supaya Buka dalam tetingkap baharu membuka panel di tempat asalnya dan bukan di halaman utama aplikasi:

  • setPanelState(state): panggil apabila panel berubah tempat, dengan rentetan pendek yang ditakrifkan oleh aplikasi anda, seperti 'note/<id>' atau 'board/<id>/card/<id>', atau null di halaman utamanya. Ia akan diletakkan dalam alamat tetingkap, jadi jangan letakkan rahsia di dalamnya. Jika keadaan melebihi 512 aksara atau mengandungi aksara kawalan, ia akan dibuang.
  • initialPanelState: dalam tetingkap baharu, keadaan yang dimiliki oleh panel, atau undefined. Anggap ia sebagai input yang tidak dipercayai: dapatkan semula item sebagai pengguna yang log masuk, dan tampilkan halaman utama aplikasi atau paparan tidak ditemui jika mereka tidak dapat membukanya.

Keadaan ini dilupakan apabila panel ditutup atau panel aplikasi lain mengambil tempatnya. Untuk membuka tetingkap panel anda sendiri, popoutRhsPlugin (juga dalam window.WebappUtils.popouts) menerima keadaan sebagai hujah kelima yang pilihan. Nota, Papan Putih, Senarai tugasan, Kanban dan Buku Taktik menggunakan ini.

fusionIcon menamakan ikon daripada set ikon Fusion (contohnya poll, sticker, calendar atau image; lihat webapp/fusion/src/fusion/components/icon). Fusion memaparkannya sebagai ganti icon, supaya item tersebut sepadan dengan yang lain.

Tetapan

settings_schema dalam plugin.json menerangkan halaman aplikasi dalam 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 tetapan: bool, text, longtext, number, dropdown, radio, generated (rahsia rawak), username, dan custom (dilukis oleh komponen yang didaftarkan oleh bahagian aplikasi web dengan registerAdminConsoleCustomSetting). Tetapan boleh dikelompokkan dalam sections.

Bahagian pelayan membacanya ke dalam struktur yang medan-medannya sepadan dengan kunci-kunci:

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
}

Pentadbir juga boleh menetapkannya dalam konfigurasi, di bawah PluginSettings.Plugins.<app id>, dengan kunci dalam huruf kecil (lihat panduan pentadbir).

Terjemahan

Antimatter diterjemahkan ke dalam 37 bahasa, dan aplikasi yang dibundel juga. Bahagian aplikasi web melakukannya seperti ini:

  1. Tulis setiap string dengan React Intl, dengan ID dan teks Inggerisnya: <FormattedMessage id='polls.create' defaultMessage='Create a poll'/> atau defineMessages. Letakkan nama aplikasi anda sebagai awalan untuk ID.
  2. Ekstrak string Inggeris ke dalam webapp/i18n/en.json (aplikasi yang dibundel menggunakan formatjs extract).
  3. Tambahkan satu fail untuk setiap bahasa di sebelahnya, dengan ID yang sama: fr.json, de.json, pt-BR.json, zh-CN.json…
  4. Beri 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);

Jika rantaian tidak wujud, ia akan kembali kepada defaultMessage dalam bahasa Inggeris. Bagi rantaian yang dihantar oleh bahagian pelayan (jawapan arahan, mesej bot), pakej pluginapi/i18n memuat fail terjemahan yang dibekalkan dalam bundle (contohnya assets/i18n) dan memberikan pelokalisator dalam bahasa setiap pengguna.

Bina, pasang dan debug

Anda perlukan Go dan Node.js (versi dalam .nvmrc aplikasi). Dalam folder aplikasi:

ArahanFungsinya
make distMembina bahagian pelayan untuk setiap platform dan bahagian aplikasi web, serta menulis bundle ke dist/<app id>-<version>.tar.gz.
make testMenjalankan ujian Go dan JavaScript.
make check-styleMenyemak kod (golangci-lint, ESLint) dan memeriksa jenis TypeScript.
make deployMembina, kemudian memasang dan membolehkan bundle pada pelayan.
make watch, make deploy-from-watchYang pertama membina bahagian aplikasi web setiap kali anda menyimpan; yang kedua membundel apa yang dibina dan memasangnya pada pelayan.
make enable, make disable, make resetMembolehkan, melumpuhkan, atau memulakan semula aplikasi pada pelayan.
make logs, make logs-watchMenunjukkan baris aplikasi dalam log pelayan.
make attachMelekatkan pengembug Delve pada bahagian pelayan yang sedang berjalan (bina dengan AM_DEBUG=1 terlebih dahulu).

make deploy dan arahan pelayan lain menggunakan soket mod tempatan apabila menemuinya (/var/tmp/antimatter_local.socket, atau AM_LOCALSOCKETPATH): jalankan pada mesin pelayan dengan mod tempatan dihidupkan. Jika tidak, ia akan log masuk ke pelayan yang diberikan oleh MM_SERVICESETTINGS_SITEURL menggunakan AM_ADMIN_TOKEN, atau AM_ADMIN_USERNAME dan AM_ADMIN_PASSWORD. Alat bina belum membaca nama AM_ untuk URL laman web.

Pasang bundle secara manual

  • Pentadbir sistem membenarkan muat naik dengan AM_PLUGINSETTINGS_ENABLEUPLOADS=true (lumpuh secara lalai; tiada suis Konsol Sistem).
  • Kemudian Konsol Sistem › Plugin › Pengurusan Plagin › Muat Naik Plagin, atau amctl plugin add weather.tar.gz diikuti dengan amctl plugin enable com.example.weather.
  • Jika pelayan mempunyai Wajibkan Tandatangan Plugin dihidupkan, ia hanya menerima bundle yang ditandatangani dengan kunci yang dipercayainya; lihat Memasang aplikasi lain.
Untuk iterasi pantas pada pelayan pembangunan, tetapkan AM_SERVICESETTINGS_ENABLEDEVELOPER=true pada pelayan: ralat kemudian membawa butiran. Fail Make aplikasi terbenam membina bahagian pelayan untuk platform anda sahaja apabila MM_SERVICESETTINGS_ENABLEDEVELOPER ditetapkan dalam shell anda.