Uygulama yazma (eklentiler)
Uygulamalar, Antimatter'e içeriden özellik ekler: sunucuya kanca (hook) ile bağlanan Go dilinde bir sunucu kısmı ve menüler, paneller, ileti türleri ve sayfalar ekleyen React dilinde bir web uygulaması kısmı. Bu sayfa, uygulamaların nasıl düzenlendiğini, örnek olarak paketlenmiş Anket (Polls) uygulamasını kullanarak ve Antimatter'in Fusion arayüzünde nelerin değiştiğini gösterir.
Bir uygulamanın çalışma şekli
- Sunucu kısmı bir Go programıdır. Sunucu, bunu ayrı bir süreç olarak başlatır ve RPC üzerinden iletişim kurar: uygulamanın kancalarını (bir iletinin gönderilmek üzere olması, bir komutun çalıştırılması…) çağırır ve uygulama, sunucunun eklenti API'sini (bir iletinin oluşturulması, bir kullanıcının okunması, veri depolanması…) çağırır. Ayrıca
/plugins/<app id>/altında HTTP yolları da sunabilir. - Web uygulaması kısmı, web uygulamasıyla birlikte tarayıcıya yüklenen bir JavaScript paketidir. registrant (kayıt defteri) ile React bileşenleri ve geri çağırma işlevleri (callback) kaydeder: bir menüdeki düğme, bir panel, bir ileti türünü çizme yöntemi.
- Herhangi bir kısım isteğe bağlıdır. Bir uygulama,
.tar.gzpaketi olarak kurulur ve sistem yöneticileri onu etkinleştirir, devre dışı bırakır ve yapılandırır.
Antimatter, Mattermost için yazılmış uygulamaları ve tersi, bir uygulama yalnızca her ikisinin de sahip olduğu kancaları kullandığı sürece çalıştırır. Yalnızca Antimatter'in sahip olduğu kancalar bölümüne bakın.
Paket düzeni
Ayrı bir başlangıç şablonu yoktur: antimatter-plugin-polls veya antimatter-plugin-todo gibi küçük bir paketlenmiş uygulamadan başlayın ve kimliğini (ID) ve kodunu değiştirin. Polls şu şekilde düzenlenmiştir:
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
İsteğe bağlı: /plugins/<app id>/public/ adresinde olduğu gibi sunulan bir public/ klasörü.
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: benzersiz ve kalıcı; genellikle tersine çevrilmiş bir alan adı kullanılır. Yolları, depolanan ayarları ve WebSocket olaylarını adlandırır.version: anlamsal sürüm (semantic version). Paketlenmiş uygulamalar bunuplugin.jsondosyasından hariç tutar; sürüm bilgilerini en sonv*git etiketinden alır.min_server_version: Antimatter12.0.0sürümünü bildirir.settings_schema: Sistem Konsolu'ndaki uygulamanın ayarlar sayfası (bkz. Ayarlar).
make apply, manifest dosyasını server/manifest.go ve webapp/src/manifest.ts dosyalarına kopyalar; make manifest-check ise doğrular.
Sunucu bölümü
Sunucu bölümü, Mattermost uygulamalarıyla aynı Go modülünü, github.com/mattermost/mattermost/server/public modülünü, Go modül vekili (proxy) üzerinden alır. main fonksiyonu yalnızca uygulamayı başlatır:
package main
import "github.com/mattermost/mattermost/server/public/plugin"
func main() {
plugin.ClientMain(&Plugin{})
}
Plugin tipi, plugin.MattermostPlugin tipini gömerek p.API erişimi sağlar ve ihtiyaç duyduğu kancaları (hooks) uygular:
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)
}
Yaygın kancalar
| Kanca | Çalışma zamanı |
|---|---|
OnActivate, OnDeactivate | Uygulama etkinleştirildiğinde veya devre dışı bırakıldığında, ayrıca sunucu başlatıldığında ve durdurulduğunda. Komutları ve botları OnActivate içinde kaydedin. |
OnConfigurationChange | Ayarları değiştiğinde; bunları p.API.LoadPluginConfiguration(&cfg) ile yükleyin. |
ServeHTTP | /plugins/<app id>/… adresine yapılan istekler. İstek bir oturum açmış kullanıcıdan geliyorsa sunucu Mattermost-User-Id başlığını ayarlar; bu başlık olmayan istekleri, herkese açık amaçlı olmadıkça reddedin. |
ExecuteCommand | Uygulamanın kaydettiği bir komut çalıştırıldığında. |
MessageWillBePosted, MessageWillBeUpdated | Bir ileti kaydedilmeden önce: değiştirilmiş bir iletiyi veya reddetme nedenini döndürün. |
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeleted | Sonradan, yan etkiler için. |
ReactionHasBeenAdded, ReactionHasBeenRemoved | Tepkiler. |
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreated | Üyelik ve kanal değişiklikleri. Bir takım, bir topluluktur. |
FileWillBeUploaded | Bir dosya saklanmadan önce: değiştirin veya reddedin. |
OnPluginClusterEvent | Kümenin (cluster) başka bir sunucusundaki aynı uygulamadan gelen bir ileti. |
Tam liste, tam imzalarla birlikte, server/public/plugin/hooks.go dosyasında; API ise server/public/plugin/api.go dosyasındadır. pluginapi paketi (server/public/pluginapi), API'yi daha kullanışlı yardımcılarla sarar.
Yararlı API çağrıları
CreatePost,UpdatePost,SendEphemeralPost: uygulamanın botu veya bir kullanıcı adına ileti gönderin.EnsureBotUser(&model.Bot{Username, DisplayName}): uygulamanın botunu bir kez oluşturun ve kimliğini (ID) alın.PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): web uygulamasına bir olay gönderin. Olay,custom_<app id>_poll_updatedolarak ulaşır.OpenInteractiveDialog: bir dialog açın.LogInfo,LogErrorve benzerleri: sunucu günlüğüne, uygulamanın kimliğiyle (ID) etiketlenmiş olarak yazın.GetUser,GetChannel,HasPermissionToChannel: bir kullanıcı adına işlem yapmadan önce, kimin ne yapabileceğini kontrol edin.
Bir uygulama, kümenin her sunucusunda çalışır. Durumu yalnızca bellekte değil, anahtar-değer deposunda veya veritabanında saklayın.
Yapay zeka servisi
Antimatter sunucusu, uygulamalar adına yapay zeka modellerine, bir yöneticinin kurduğu model bağlantıları aracılığıyla (yönetici kılavuzundaki Yapay Zeka bölümüne bakın) istek gönderir. Bir uygulama asla bir sağlayıcının anahtarını tutmaz: hangi kişi adına ve nerede hareket ettiğini belirtir; sunucu, bu kişinin orada bu bağlantıyı kullanıp kullanamayacağını kontrol eder, sınırlarını ve bütçelerini uygular, tokenleri kişi ve uygulama adına sayar ve içeriği denetlemeden çağrıyı denetler.
| Yöntem | Ne işe yarar |
|---|---|
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest) | Sohbet tamamlama: iletiler, araçlar, yapılandırılmış çıktı (JSONSchema). |
AIChatStream(…) | Aynı işlem, akış halinde: kanal kapanana kadar akışın Events değerlerini okuyun veya çağrıyı durdurmak için Close çağrısı yapın. |
AIEmbed(…, *ai.EmbedRequest) | Metinlerin gömme (embedding) değerleri. |
AITranscribe(…, *ai.TranscribeRequest) | Sesin metne dönüştürülmesi. |
AIDecide(…, *ai.DecideRequest) | Bir metin hakkında karar modeline (evet veya hayır, bir seçim, bir puan) yöneltilen tiplemiş sorular. |
AIConnectionsForUser(userID, channelID, teamID) | Bir kişinin orada kullanabileceği bağlantılar, modelleri ve yetenekleriyle birlikte; asla anahtarlarıyla değil. |
Her isteğin ConnectionID değeri bağlantıyı, Model değeri ise bu bağlantının modellerinden birini seçer (boş bırakılırsa bağlantının varsayılanı kullanılır). Operation, kullanım ve denetim kayıtları için kısa bir etikettir; asla içerik değildir. Bunların minimum sunucu sürümü 11.11'dir.
actingUserID değerini yalnızca sunucunun doğruladığı bir kaynaktan alın: ServeHTTP adresinize gelen isteğin Mattermost-User-Id başlığı veya bir kancanın bağlamındaki kullanıcı (bir gönderinin yazarı, bir komutu çalıştıran kullanıcı). Asla bir iletiden, bir webhook yükünden, bir URL'den veya başka bir uygulamanın isteğinden almayın: uygulamanız, başka bir kişinin erişimini harcar.Bu yöntemler ve ai paketi (server/public/ai), yalnızca Antimatter'in modül kopyasında mevcuttur; Mattermost tarafından yayınlanan sürümde bulunmaz. Bunları kullanmak için, go.mod dosyanızda bir replace satırıyla Antimatter'in server/public dizinine karşı derleme yapın; örneğin replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public. Bu tür bir uygulama yalnızca Antimatter üzerinde çalışır.
Veri saklama
Her uygulamanın, sunucunun veritabanında kendi anahtar-değer deposu vardır:
KVSet(key, value),KVGet(key),KVDelete(key): değerler bayt olarak, genellikle JSON biçimindedir. Anahtarlar en fazla 150 karakter olabilir.KVSetWithExpiry(key, value, seconds): değer bu süre dolunca silinir.KVCompareAndSet(key, old, new)veAtomicileKVSetWithOptions: birden fazla istek veya sunucu aynı anahtarı yazarken güvenli güncellemeler sağlar. Anket, her oyu bu şekilde kaydeder ve çakışma durumunda yeniden dener.KVList(page, perPage): anahtarlar, sayfa sayfa listelenir.
Web uygulaması bölümü
Yığın (bundle), window.registerPlugin ile bir sınıf kaydeder. initialize metodu kayıt defterini (registry) ve Redux deposunu alır:
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());
- Paylaşılan kütüphaneler. Web uygulaması React, ReactDOM, Redux, React Redux ve React Intl sağlar: bunları kendi kopyalarınızı yığmak (bundle) yerine webpack
externalsolarak listeleyin (React,ReactDOM,Redux,ReactRedux,ReactIntl). Anket'inwebpack.config.jsdosyasına bakın. - Sunucu bölümünüzü çağırma.
${window.basename}/plugins/<app id>/…adresini,Client4.getOptions()(kaynağımattermost-redux/client) ile gelen seçenekleri kullanarak getirin (fetch): bu seçenekler, sunucunun tarayıcıdan gelen isteği kabul etmesi için gereken başlıkları taşır. - Kendi durumunuz.
registerReducerbir reducer ekler; bu,state['plugins-<app id>']altında saklanır. - Tipler. Antimatter'in ek kayıt defteri (registry) yöntemleri, Mattermost'un yayımladığı tiplerde yer almaz: Anket, kullandığı kayıt defterini
webapp/src/types/host.tsdosyasında tanımlar.
Kayıt defterinin (registry) yöntemleri ve parametreleri, webapp/fusion/src/plugins/registry.ts (Fusion) ve webapp/channels/src/plugins/registry.ts (klasik) dosyalarındaki kodda belgelenmiştir.
Fusion arayüzünü destekleme
Antimatter'in iki web arayüzü vardır: varsayılan olan Fusion ve klasik arayüz. İkisi de aynı uygulama yığınlarını (bundle) yükler ve aynı kayıt defterine (registry) sahiptir, ancak Fusion birçok öğeyi kendisi çizer ve eklenti bileşenlerini kendi yöntemine göre yerleştirir. Uygulamanızı her iki arayüzde de test edin.
Arayüzü algılama
Herhangi bir uygulama yüklenmeden önce, her iki arayüz de window.antimatterWebUI değerini 'fusion' veya 'classic' olarak ayarlar ve aynı değeri sayfanın kök öğesinde data-am-web-ui olarak belirler. Mattermost'ta bu değerlerden hiçbiri ayarlanmaz.
export function isFusionUI(): boolean {
return window.antimatterWebUI === 'fusion' || document.documentElement.dataset.amWebUi === 'fusion';
}
Yerleşik uygulamalar, arayüzü farklı şekilde çizmek için bunu kullanır. Anketler, anket kartlarını ve oluşturma iletişim kutusunu Fusion stiline göre çizer ve Fusion'daki /poll komutu için kendi iletişim kutusunu açar. Aramalar ve Ses kanalları, Fusion'un kendi arama arayüzüyle değiştirdiği kenar çubuğu ve bildirim bileşenlerini hariç tutar. Ajanlar uygulaması, AI işlemlerini, kaydırma araç çubuğu yerine Diğer işlemler altında bir grup olarak ileti menüsüne yerleştirir. Bu uygulamaların arayüzle uyumlu olması için kullandığı şey, Fusion'un kendi CSS sınıfları (am- önekiyle) ve iletişim kutusu katmanı (am-layer öğesi)dir; bunlar belgelenmiş ve kararlı bir API değildir.
Fusion'un eklenti bileşenlerini gösterdiği yerler
| Kayıt yöntemi | Fusion'da göründüğü yer |
|---|---|
registerAppBarComponent, registerChannelHeaderButtonAction | Uygulama rayı, sağ kenarda avatarınız ile Antimatter hakkında düğmesi arasındaki simge sütunu. Kanal başlığı düğmeleri de oraya gider, kanal başlığına değil. Sistem yöneticisi Uygulamalar çubuğu kullanılmasın (ExperimentalSettings.DisableAppBar, varsayılan olarak kapalı) seçeneğini açtığında gizlenir. |
registerRightHandSidebarComponent | Sağdaki panel. Kullanıcılar, kenarını sürükleyerek boyutlandırabilir ve yeni bir pencerede açabilir. Uygulama aynı zamanda bir ürünse, panel Tam sayfa olarak aç seçeneğini sunar. Yeni penceredeki panel bölümüne bakın. |
registerChannelHeaderIcon | Kanal başlığındaki arama düğmesinin ardından gelen simgeler; telefonlarda başlığın Diğer menüsünde. |
registerCallButtonAction | Kanal başlığındaki arama düğmesi; birden fazla sağlayıcı Arama yapmanın diğer yolları menüsünü paylaşır. |
registerPostDropdownMenuAction | İletinin İleti işlemleri (⋯) menüsündeki Diğer işlemler alt menüsü; ayrıca konu panelindeki Konu işlemleri menüsünde, Diğer işlemler altında. Fusion, her işlemin önünde uygulamanın simgesini gri renkte çizer: yerleşik uygulamalar için kendi simgesi, aksi halde uygulamanın uygulama rayında gösterdiği simge, yoksa nötr bir simge. İşletme metninin başında metin içermeyen bir öğe (uygulamanın kendisinin çizdiği simge) gizlenir. |
registerPostDropdownSubMenuAction | Tekil işlemlerden sonra, aynı Diğer işlemler alt menüsünde bir başlık içeren grup. Hiçbir uygulama, ileti menüsünde kendi başına bir girişe sahip olmaz. |
registerPostActionComponent | İletinin üzerine gelinen araç çubuğu, ⋯ düğmesinden önce. |
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponent | İletinin kendisi: gövdesi, metninin altında, zamanının ardından ve bağlantı önizlemelerinin yerinde. |
registerChannelHeaderMenuAction | Kanalın Kanal ayarları menüsü (kenar çubuğundaki bir kanalda ⋯ veya sağ tık), fiş simgeli öğeler olarak. |
registerMainMenuAction | Topluluk menüsü (kanal listesinin üstündeki topluluğun adı), Diğer işlemler altında, uygulamaya göre gruplandırılmış. |
registerSidebarBrowseOrAddChannelMenuAction | Topluluk menüsü, Kanal oluştur ve Kategori oluştur ardından. |
registerFileUploadMethod | Yazma alanının + menüsü (İletiye ekle), Dosya yükle öğesinin ardından. |
registerPostEditorActionComponent | Yazma alanının biçimlendirme çubuğu, biçimlendirme gösterildiğinde. |
registerAIActionMenuItemComponent | Yazma alanının Yapay zekâ menüsü. |
registerFileDropdownMenuAction, registerFilePreviewComponent | Bir dosyanın seçenek menüsü ve dosya önizlemesi. |
registerUserSettings | Profil ve ayarlar, Uygulama ekleri başlığı altında her uygulama için bir sekme. |
registerChannelSettingsTab | Kanal ayarları penceresi, Uygulamalar başlığı altında. |
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponent | Bir adın veya profil fotoğrafının üzerine tıklandığında görünen profil kartı. |
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponent | Bir topluluğun kanal listesinin üst kısmı, bir kanalın adının yanında, kanal simgesinin yanında ve sol taraftaki topluluk rayının alt kısmı. |
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholder | Bir kanalın geçmişinin başlangıcı, ileti listesinin üst kısmı, okunmamış satırı, yazma alanının üstü ve yazma alanının yer tutucusu. |
registerChannelTypeOption | Kanal oluştur iletişim kutusunun kanal türleri. |
registerSearchComponents | Kanal başlığının arama kutusu: boş olduğunda uygulama kapsamları görünür. |
registerUserGuideDropdownMenuAction | Antimatter hakkında (uygulama rayının alt kısmı), Yardım altında. |
registerProduct | Ürünün URL'sindeki tam sayfalar, Antimatter hakkında bölümünde Ürünler altında listelenir. Ürün sayfaları, klasik sayfa çerçevesini korur; ürün menüsü yalnızca bir uygulama ürün kaydeder veya ona bir giriş eklediğinde görünür. Yerleşik Kanban ve Playbooklar uygulamaları artık ürün kaydetmez: sayfaları yan panellerinde açılır. |
registerRootComponent, registerGlobalComponent, registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer, registerTranslations gibi kancalar | Klasik arayüzdeki gibi çalışır. |
registerAdminConsolePlugin, registerAdminConsoleCustomSetting | Her iki arayüzde de klasik olan Sistem Konsolu. |
Fusion'un göstermediği veya çalıştırmadığı öğeler
registerPostDropdownMenuComponent(ilet menüsündeki bir bileşen),registerPostCardTypeComponent(sağdaki paneldeki bir gönderinin kartı) veregisterProductSwitcherMenuItem, Fusion'un ana görünümlerinde gösterilmez. İlki yerineregisterPostDropdownMenuActionkullanın.registerMessageWillBeUpdatedHook, Fusion'da bir iletinin düzenlendiğinde çalışmaz. Düzenlemeleri sunucudaMessageWillBeUpdatedkancasıyla kontrol edin.registerActionAfterChannelCreationyalnızca klasik kanal oluşturma iletişim kutusundan çalışır; Fusion bunu Kanal oluştur iletişim kutusundaki Diğer seçenekler… öğesinden açar.- Uygulama çubuğu bileşenleri,
supportedProductIdsdeğerleri ne olursa olsun gösterilir. registerNeedsTeamRouteveregisterCustomRoutekaynaklı rotalar, ürünler gibi klasik sayfa çerçevesini korur.
Yalnızca Antimatter'da bulunan kancalar
Bu kayıt yöntemleri Mattermost'ta mevcut değildir. Uygulamanın orada da çalışabilmesi için bir yöntemi çağırmadan önce mevcut olup olmadığını kontrol edin:
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');
}
| Yöntem | Ne ekler |
|---|---|
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender}) | Her iki arayüzde de ilet kutusunun + menüsünde bir öğe. action, {channelId, rootId} alır. |
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker}) | İleti kutusunun emoji seçicisindeki bir sekme, örneğin GIF'ler veya çıkartmalar. Fusion'da, order değeri 10'dan düşük olan sekmeler Emoji sekmesinden önce gelir. Bileşen channelId, rootId, filter, onFilterChange, onSelectDone, insertText, isFusion ve Fusion'da pickerKit (aşağıda) parametrelerini alır. |
registerChannelViewPanel({matcher, component}) | Kanal başlığı ile iletiler arasında, matcher(state, channel) tarafından seçilen kanallar için bir panel. Ses kanallarının yaptığı gibi iletileri ve yazma alanını gizleyebilir (setMessagesVisible). |
registerSidebarChannelFooterComponent(component) | Kenar çubuğundaki bir kanalın altındaki satır, örneğin arama içindeki kişiler. channel değerini alır. |
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender}) | Yalnızca Fusion: Bütünleştirmeler sayfalarındaki bir giriş, özel emojilerin yanında. GIF uygulaması özel GIF'lerini ve çıkartmalarını oraya ekler. |
Emoji seçicideki görünümleri ekleyin ve yönetin
Fusion'da bir emoji seçici sekmesi pickerKit özelliğine (prop) sahip olur: Emoji sekmesinin kendi ekleme ve yönetme görünümleri için kullandığı bileşenler, böylece bir sekmenin görünümleri aynı görünüme sahip olur ve seçici içinde kalır. GIFs ve Memes uygulamaları GIF'leri, çıkartmaları ve meme şablonlarını eklemek ve yönetmek için bunu kullanır. version (1), usePickerView ve useOnEscape hook'larını, PickerViewButtons (arama kutusunun yanındaki + ve yönetme düğmeleri), PickerViewFrame (geri oku olan bir görünüm), PickerNotice, PickerField, PickerSearch, PickerDropZone ve PickerManageList bileşenlerini içerir. Escape tuşu, bir görünümden sekmenin ızgarasına geri döner. Özelliğin mevcut olduğundan emin olun: diğer konaklar (hosts) bunu hariç tutar ve bu durumda sekme kendi diyaloglarını korur. Tipler webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) ve bileşenler webapp/fusion/src/fusion/popovers/picker_views.tsx dosyasında bulunur.
Paneli yeni bir pencerede
Fusion, registerRightHandSidebarComponent bileşenine iki ek prop verir; böylece Yeni pencerede aç paneli uygulama ana sayfasında değil, bulunduğu yerde açar:
setPanelState(state): panel yer değiştirdiğinde çağırın. Kısa bir dize, örneğin'note/<id>'veya'board/<id>/card/<id>', veya ana sayfasındanullkullanın. Bu değer pencerenin adresine yazılır, bu yüzden gizli bilgiler asla içermemelidir. 512 karakterden uzun veya denetim karakterleri içeren durumlar düşürülür.initialPanelState: yeni pencerede panelin sahip olduğu durum veyaundefined. Bunu güvensiz bir girdi olarak ele alın: öğeyi oturum açan kişi olarak yeniden getirin ve kişi öğeyi açamıyorsa uygulamanın ana sayfasını veya bulunamadı görünümünü gösterin.
Panel kapatıldığında veya başka bir uygulamanın paneli onun yerini aldığında durum unutulur. Bir panelin penceresini kendiniz açmak için popoutRhsPlugin (aynı zamanda window.WebappUtils.popouts içinde) durumu isteğe bağlı beşinci argüman olarak alır. Not, Beyaz tahta, Yapılacaklar, Kanban ve Playbook'lar bunu kullanır.
fusionIcon, Fusion'un simge setindeki bir simgeyi belirtir (örneğin poll, sticker, calendar veya image; bkz. webapp/fusion/src/fusion/components/icon). Fusion, icon yerine bunu gösterir, böylece öğe diğerleriyle uyumlu olur.
Ayarlar
plugin.json içindeki settings_schema, uygulamanın Sistem Konsolu › Uygulama ekleri sayfasını açıklar:
"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."}
]
}
Ayar türleri: bool, text, longtext, number, dropdown, radio, generated (rastgele bir gizli anahtar), username ve custom (web uygulaması bölümünün registerAdminConsoleCustomSetting ile kaydettiği bir bileşen tarafından çizilir). Ayarlar sections içinde gruplandırılabilir.
Sunucu bölümü, alanları anahtarlarla eşleşen bir yapıya (struct) okur:
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
}
Yöneticiler, bunları yapılandırmada, PluginSettings.Plugins.<app id> altında, küçük harfli anahtarlarla da ayarlayabilir (bkz. yönetici kılavuzu).
Çeviriler
Antimatter 37 dile çevrilmiştir ve paketlenen uygulamalar da öyle. Web uygulaması bölümü bunu şu şekilde yapar:
- Tüm dizeleri React Intl ile, bir kimlik (ID) ve İngilizce metniyle yazın:
<FormattedMessage id='polls.create' defaultMessage='Create a poll'/>veyadefineMessages. Kimliklerin başına uygulamanızın adını ekleyin. - İngilizce dizeleri
webapp/i18n/en.jsondosyasına çıkarın (paketlenen uygulamalarformatjs extractkullanır). - Yanına, aynı kimliklere sahip her dil için bir dosya ekleyin:
fr.json,de.json,pt-BR.json,zh-CN.json… - Bunları web uygulamasına verin; kullanıcıdan dilini ister:
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);
Eksik bir dize, İngilizce defaultMessage değerine geri düşer. Sunucu tarafının gönderdiği dizeler için (komut yanıtları, bot iletileri) pluginapi/i18n paketi, paketle birlikte gelen çeviri dosyalarını (örneğin assets/i18n) yükler ve her kullanıcı için kendi dilinde bir yerelleştirici sağlar.
Derleme, kurulum ve hata ayıklama
Go ve Node.js (uygulamanın .nvmrc dosyasındaki sürüm) gerekir. Uygulamanın klasöründe:
| Komut | Ne işe yarar |
|---|---|
make dist | Sunucu tarafını her platform için ve web uygulaması tarafını derler, paketi dist/<app id>-<version>.tar.gz konumuna yazar. |
make test | Go ve JavaScript testlerini çalıştırır. |
make check-style | Kodu denetler (golangci-lint, ESLint) ve TypeScript türlerini kontrol eder. |
make deploy | Derler, ardından paketi sunucuya kurar ve etkinleştirir. |
make watch, make deploy-from-watch | İlk komut her kaydedişte web uygulaması tarafını yeniden derler; ikinci komut derlediği içeriği paketler ve sunucuya kurar. |
make enable, make disable, make reset | Uygulamayı sunucuda etkinleştirir, devre dışı bırakır veya yeniden başlatır. |
make logs, make logs-watch | Sunucu günlüğündeki uygulamanın satırlarını gösterir. |
make attach | Çalışan sunucu tarafına Delve hata ayıklayıcısını bağlar (önce AM_DEBUG=1 ile derleyin). |
make deploy ve diğer sunucu komutları, bir yerel mod soketi bulduklarında onu kullanır (/var/tmp/antimatter_local.socket veya AM_LOCALSOCKETPATH): bunları yerel mod açıkken sunucunun makinesinde çalıştırın. Aksi halde MM_SERVICESETTINGS_SITEURL ile belirtilen sunucuya AM_ADMIN_TOKEN veya AM_ADMIN_USERNAME ve AM_ADMIN_PASSWORD ile giriş yaparlar. Derleme araçları henüz site URL'si için bir AM_ adını okumaz.
Bir paketi elle kurun
- Bir sistem yöneticisi,
AM_PLUGINSETTINGS_ENABLEUPLOADS=trueayarıyla yüklemelere izin verir (varsayılan olarak kapalıdır; Sistem Konsolu'nda bir anahtarı yoktur). - Ardından Sistem Konsolu › Uygulama ekleri › Uygulama eki yönetimi › Uygulama eki yükle veya
amctl plugin add weather.tar.gzardındanamctl plugin enable com.example.weather. - Sunucuda Uygulama eki imzası istensin seçeneği açıksa, yalnızca güvendiği bir anahtarla imzalanmış paketleri kabul eder; bkz. Diğer uygulamaların yüklenmesi.
AM_SERVICESETTINGS_ENABLEDEVELOPER=true ayarını yapın: hatalar bu durumda ayrıntılarını taşır. Paketlenmiş uygulamaların Makefile'ları, kabuğunuzda MM_SERVICESETTINGS_ENABLEDEVELOPER ayarlıysa sunucu tarafını yalnızca sizin platformunuz için derler.