ایپس (پلگ انز) لکھنا

ایپس Antimatter کو اندر سے خصوصیات فراہم کرتی ہیں: Go میں سرور کا حصہ جو سرور میں ہک ہوتا ہے، اور React میں ویب ایپ کا حصہ جو مینو، پینلز، پیغام کے اقسام اور صفحات شامل کرتا ہے۔ یہ صفحہ دکھاتا ہے کہ ایک ایپ کیسے ترتیب دی جاتی ہے، جہاں شامل شدہ Polls ایپ کو مثال کے طور پر استعمال کیا گیا ہے، اور Antimatter کے Fusion انٹرفیس میں کیا تبدیلیاں آتی ہیں۔

ایپ کیسے کام کرتی ہے

  • سرور کا حصہ ایک Go پروگرام ہے۔ سرور اسے ایک الگ پروسیس کے طور پر شروع کرتا ہے اور اس کے ساتھ RPC کے ذریعے بات چیت کرتا ہے: یہ ایپ کے ہکس کو کال کرتا ہے (ایک پیغام پوسٹ ہونے والا ہے، ایک کمانڈ چلائی گئی ہے…)، اور ایپ سرور کے پلگ ان API کو کال کرتی ہے (پوسٹ بنائیں، صارف پڑھیں، ڈیٹا محفوظ کریں…)۔ یہ /plugins/<app id>/ کے تحت HTTP روٹس بھی فراہم کر سکتی ہے۔
  • ویب ایپ کا حصہ ایک JavaScript بंडل ہے جو ویب ایپ کے ساتھ براؤزر میں لوڈ ہوتا ہے۔ یہ رجسٹری کے ساتھ React اجزاء اور کال بیکس رجسٹر کرتا ہے: مینو میں بٹن، پینل، یا پیغام کے کسی قسم کو ڈرا کرنے کا طریقہ۔
  • دونوں حصے اختیاری ہیں۔ ایک ایپ .tar.gz بंडل کے طور پر انسٹال ہوتی ہے، اور سسٹم ایڈمنز اسے فعال، غیر فعال اور ترتیب دیتے ہیں۔
سرور کا حصہ سرور کے ڈیٹا تک مکمل رسائی کے ساتھ چلتا ہے۔ ایپ کو اس طرح سمجھیں جیسے آپ سرور پر ڈپلوائے ہونے والا کوڈ۔

Antimatter Mattermost کے لیے لکھی گئی ایپس کو چلاتا ہے، اور اس کے برعکس بھی، بشرطیکہ ایپ صرف ان ہکس کا استعمال کرے جو دونوں میں موجود ہیں۔ دیکھیں صرف Antimatter کے ہکس۔

بंडل کی ترتیب

کوئی الگ اسٹارٹر ٹیمپلیٹ موجود نہیں ہے: ایک چھوٹی شامل شدہ ایپ جیسے antimatter-plugin-polls یا antimatter-plugin-todo سے شروع کریں، اور اس کا ID اور کوڈ تبدیل کریں۔ Polls کی ترتیب اس طرح ہے:

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

اختیاری: ایک public/ فولڈر، جو /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: منفرد اور مستقل؛ ایک ریورس ڈومین نام عام طور پر استعمال ہوتا ہے۔ یہ روٹس، محفوظ شدہ ترتیبات اور WebSocket ایونٹس کے نام مقرر کرتا ہے۔
  • version: سیمنٹک ورژن۔ شامل شدہ ایپس اسے plugin.json سے باہر چھوڑ دیتی ہیں؛ ان کا بلڈ ٹول اسے تازہ ترین v* git ٹیگ سے لیتا ہے۔
  • min_server_version: Antimatter 12.0.0 رپورٹ کرتا ہے۔
  • settings_schema: سسٹم کنسول میں ایپ کی ترتیبات کی صفحہ (دیکھیں ترتیبات)۔

make apply مانی فیسٹ کو server/manifest.go اور webapp/src/manifest.ts میں کاپی کرتا ہے؛ make manifest-check اس کی تصدیق کرتا ہے۔

سرور کا حصہ

سرور کا حصہ Mattermost ایپس کے جیسا ہی Go ماڈیول، github.com/mattermost/mattermost/server/public، Go ماڈیول پروکسی سے امپورٹ کرتا ہے۔ اس کا main صرف ایپ کو شروع کرتا ہے:

package main

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

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

Plugin ٹائپ plugin.MattermostPlugin کو ایمبیڈ کرتا ہے، جس سے اسے p.API ملتا ہے، اور وہ ہکس (hooks) کو نافذ کرتا ہے جو اسے درکار ہیں:

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)
}

عام ہکس

ہککب چلتا ہے
OnActivate, OnDeactivateجب ایپ کو فعال یا غیر فعال کیا جائے، اور جب سرور شروع ہو یا بند ہو۔ OnActivate میں کمانڈز اور بوٹس رجسٹر کریں۔
OnConfigurationChangeجب اس کی ترتیبات تبدیل ہوں؛ انہیں p.API.LoadPluginConfiguration(&cfg) کے ذریعے لوڈ کریں۔
ServeHTTP/plugins/<app id>/… کی درخواستیں۔ جب درخواست سائنڈ ان صارف سے آتی ہے تو سرور Mattermost-User-Id ہیڈر سیٹ کرتا ہے؛ اس کے بغیر درخواستوں کو مسترد کریں، مگر یہ سوائے اس کے کہ وہ عوامی ہونے کا مقصد رکھتی ہوں۔
ExecuteCommandایپ نے رجسٹر کی ہوئی کمانڈ چلا دی گئی۔
MessageWillBePosted, MessageWillBeUpdatedپیغام محفوظ ہونے سے پہلے: تبدیل شدہ پوسٹ واپس کریں، یا اسے مسترد کرنے کی وجہ دیں۔
MessageHasBeenPosted, MessageHasBeenUpdated, MessageHasBeenDeletedبعد ازاں، جانبی اثرات کے لیے۔
ReactionHasBeenAdded, ReactionHasBeenRemovedردعمل۔
UserHasJoinedChannel, UserHasLeftChannel, UserHasJoinedTeam, UserHasLeftTeam, ChannelHasBeenCreatedرکنیت اور چینلز میں تبدیلیاں۔ ٹیم ایک کمیونٹی ہے۔
FileWillBeUploadedفائل محفوظ ہونے سے پہلے: اسے تبدیل کریں یا مسترد کریں۔
OnPluginClusterEventکلسٹر کے دوسرے سرور پر موجود اسی ایپ سے پیغام۔

مکمل فہرست، بالکل درست سائنچرز کے ساتھ، server/public/plugin/hooks.go میں ہے؛ API server/public/plugin/api.go میں ہے۔ pluginapi پیکیج (server/public/pluginapi) API کو دوستانہ ہیلپرز میں لفٹ کرتا ہے۔

مفید API کالز

  • CreatePost، UpdatePost، SendEphemeralPost: ایپ کے بوٹ کے طور پر یا کسی صارف کے طور پر پوسٹ کریں۔
  • EnsureBotUser(&model.Bot{Username, DisplayName}): ایپ کا بوٹ ایک بار بنائیں اور اس کا ID حاصل کریں۔
  • PublishWebSocketEvent("poll_updated", payload, &model.WebsocketBroadcast{ChannelId: id}): ویب ایپ کو ایونٹ بھیجیں۔ یہ custom_<app id>_poll_updated کے طور پر پہنچتا ہے۔
  • OpenInteractiveDialog: ڈائیلاگ کھولیں۔
  • LogInfo، LogError اور اسی طرح کے: سرور لاگ میں لکھیں، ایپ کے ID کے ساتھ ٹیگ شدہ۔
  • GetUser، GetChannel، HasPermissionToChannel: کسی صارف کے لیے عمل کرنے سے پہلے چیک کریں کہ کس کو کیا کرنے کی اجازت ہے۔

ایپ کلسٹر کے ہر سرور پر چلتی ہے۔ اسٹیٹ کو کیو وی اسٹور یا ڈیٹا بیس میں رکھیں، صرف میموری میں نہیں۔

AI سروس

Antimatter کا سرور ایپس کے لیے AI ماڈلز کو کال کرتا ہے، اس کے لیے ایڈمن نے جو ماڈل کنکشنز سیٹ اپ کیے ہیں (ایڈمن گائیڈ میں AI دیکھیں)۔ کوئی ایپ پرووائیڈر کی کلڈ نہیں رکھتی: یہ صرف اس شخص کا نام بتاتی ہے جس کے لیے وہ کام کر رہی ہے اور کہاں، اور سرور چیک کرتا ہے کہ کیا وہ شخص وہاں اس کنکشن کا استعمال کر سکتا ہے، اس کی حدود اور بجٹ لاگو کرتا ہے، ٹوکنز کو اس شخص اور ایپ کے حساب سے گنتی کرتا ہے، اور کال کی آڈٹ ریکارڈ کرتا ہے بغیر اس کے مواد کے۔

طریقہیہ کیا کرتا ہے
AIChat(actingUserID, channelID, teamID, *ai.ChatRequest)ایک چیٹ کمپلیشن: پیغامات، ٹولز، اور ساختی آؤٹ پٹ (JSONSchema)۔
AIChatStream(…)وہی، اسٹریمنگ کے ساتھ: چینل بند ہونے تک اسٹریم کے Events پڑھیں، یا کال روکنے کے لیے اسے Close کریں۔
AIEmbed(…, *ai.EmbedRequest)متن کے ایمبیڈنگز۔
AITranscribe(…, *ai.TranscribeRequest)بول چال کو متن میں تبدیل کرنا۔
AIDecide(…, *ai.DecideRequest)ایک متن کے بارے میں فیصلہ ماڈل کو ٹائپڈ سوالات (ہاں یا نہیں، ایک انتخاب، ایک اسکور)۔
AIConnectionsForUser(userID, channelID, teamID)وہ کنکشنز جو ایک شخص وہاں استعمال کر سکتا ہے، ان کے ماڈلز اور صلاحیتوں کے ساتھ، کبھی ان کی کلڈز کے ساتھ نہیں۔

ہر درخواست کا ConnectionID کنکشن منتخب کرتا ہے، اور Model اس کا ایک ماڈل (اگر خالی ہو تو کنکشن کا ڈیفالٹ)۔ Operation استعمال اور آڈٹ ریکارڈز کے لیے ایک مختصر لیبل ہے، کبھی مواد نہیں۔ ان کا کم از کم سرور ورژن 11.11 ہے۔

actingUserID کو صرف اس ماخذ سے لیں جو سرور نے تصدیق کر لیا ہو: آپ کے ServeHTTP کی درخواست کا Mattermost-User-Id ہیڈر، یا ہک کے کنٹیکسٹ کا صارف (پوسٹ کے مصنف، یا وہ صارف جس نے کمانڈ چلائی)۔ کبھی اسے پیغام، ویب ہک پی لوڈ، URL یا کسی دوسری ایپ کی درخواست سے نہ لیں: ورنہ آپ کی ایپ کسی اور کے رسائی کے وسائل خرچ کر دے گی۔

یہ طریقے اور ai پیکیج (server/public/ai) صرف Antimatter کے ماڈل کی کاپی میں موجود ہیں، Mattermost کے پبلش شدہ ورژن میں نہیں۔ ان کا استعمال کرنے کے لیے، Antimatter کے server/public کے خلاف بلڈ کریں، اپنے go.mod میں ایک replace لائن کے ساتھ، مثال کے طور پر replace github.com/mattermost/mattermost/server/public => ../antimatter/server/public۔ ایسی ایپ صرف Antimatter پر چلے گی۔

ڈیٹا کا ذخیرہ

ہر ایپ کے لیے سرور کے ڈیٹا بیس میں اپنا الگ کیو وی اسٹور ہوتا ہے:

  • KVSet(key, value), KVGet(key), KVDelete(key): ویلیوز بائٹس ہوتی ہیں، عموماً JSON۔ کیز زیادہ سے زیادہ 150 حروف کے ہو سکتے ہیں۔
  • KVSetWithExpiry(key, value, seconds): ویلیو اس وقت کے بعد غائب ہو جاتی ہے۔
  • KVCompareAndSet(key, old, new) اور KVSetWithOptions کے ساتھ Atomic: جب کئی درخواستیں یا سرورز ایک ہی کی پر لکھتے ہوں تو محفوظ اپڈیٹس۔ پولز اس طریقے سے ہر ووٹ محفوظ کرتا ہے اور تصادم پر دوبارہ کوشش کرتا ہے۔
  • KVList(page, perPage): کیز، صفحہ بہ صفحہ۔

ویب ایپ کا حصہ

بندل window.registerPlugin کے ذریعے ایک کلاس رجسٹر کرتا ہے۔ اس کا initialize رجسٹری اور 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());
  • مشترک لائبریریاں۔ ویب ایپ React، ReactDOM، Redux، React Redux اور React Intl فراہم کرتی ہے: انہیں webpack externals (React, ReactDOM, Redux, ReactRedux, ReactIntl) کے طور پر درج کریں، اپنے کاپیوں کو بندل کرنے کے بجائے۔ Polls کے webpack.config.js کو دیکھیں۔
  • اپنے سرور حصے کو کال کرنا۔ ${window.basename}/plugins/<app id>/… کو Client4.getOptions() (جو mattermost-redux/client سے آتا ہے) کے آپشنز کے ساتھ Fetch کریں: یہ وہ ہیڈرز ہیں جو سرور کو براؤزر سے آنے والی درخواست کو قبول کرنے کے لیے درکار ہوتی ہیں۔
  • آپ کا اپنا اسٹیٹ۔ registerReducer ایک ریڈیوسر شامل کرتا ہے، جو state['plugins-<app id>'] کے تحت محفوظ ہوتا ہے۔
  • ٹائپس۔ Antimatter کے اضافی رجسٹری طریقے Mattermost کے شائع شدہ ٹائپس میں شامل نہیں ہیں: Polls webapp/src/types/host.ts میں وہ رجسٹری اعلان کرتا ہے جسے استعمال کرتا ہے۔

رجسٹری کے طریقے اور ان کے پیرامیٹرز کوڈ میں دستاویزات کے طور پر موجود ہیں، webapp/fusion/src/plugins/registry.ts (Fusion) اور webapp/channels/src/plugins/registry.ts (classic) میں۔

Fusion انٹرفیس کی معاونت

Antimatter کے دو ویب انٹرفیس ہیں: Fusion، جو ڈیفالٹ ہے، اور کلاسیکی۔ دونوں ایک جیسے ایپ بندلز لوڈ کرتے ہیں اور ایک جیسی رجسٹری رکھتے ہیں، لیکن Fusion کئی چیزیں خود بناتا ہے اور پلگ ان اجزاء کو اپنی طرز پر رکھتا ہے۔ اپنی ایپ کو دونوں میں ٹیسٹ کریں۔

انٹرفیس کی شناخت

کسی بھی ایپ کے لوڈ ہونے سے پہلے، دونوں انٹرفیس window.antimatterWebUI کو 'fusion' یا 'classic' پر سیٹ کرتے ہیں، اور اسی ویلیو کو صفحے کے روٹ عنصر پر data-am-web-ui کے طور پر۔ Mattermost پر، نہ تو یہ سیٹ ہوتا ہے۔

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

باندل شدہ ایپس اس کے استعمال سے مختلف انداز میں ڈرائے کرتی ہیں۔ پولز اپنی پول کارڈز اور تخلیق کے ڈائیلاگ کو Fusion کے انداز میں ڈرائے کرتی ہے، اور Fusion میں /poll کے لیے اپنا الگ ڈائیلاگ کھولتی ہے۔ کالز اور وائس چینلز وہ سائیڈ بار اور ٹوسٹ کمپوننٹس چھوڑ دیتے ہیں جن کی جگہ Fusion اپنی کال انٹرفیس رکھتی ہے۔ ایجنٹس ایپ اپنے AI اقدامات کو پیغام کے مینیو میں، مزید اقدامات کے نیچے ایک گروپ کے طور پر رکھتی ہے، ہاور ٹول بار کے بجائے۔ Fusion کی اپنی CSS classes (جو am- سے شروع ہوتی ہیں) اور اس کا ڈائیلاگ لیئر (am-layer عنصر) وہ چیزیں ہیں جن کا ان ایپس کو انٹرفیس کو میچ کرنے کے لیے استعمال ہوتا ہے؛ یہ دستاویزی شدہ، مستحکم API نہیں ہیں۔

جہاں فیوژن پلگ ان کمپوننٹس دکھاتا ہے

رجسٹری طریقہفیوژن میں کہاں ظاہر ہوتا ہے
registerAppBarComponent, registerChannelHeaderButtonActionایپ ریل، یعنی دائیں کنارے پر آئیکنز کی کالم، جو آپ کے ایواٹار اور Antimatter کے بارے میں بٹن کے درمیان ہے۔ چینل ہیڈر کے بٹن بھی اسی جگہ آتے ہیں، چینل ہیڈر میں نہیں۔ جب سسٹم ایڈمن ایپس بار غیر فعال کریں (ExperimentalSettings.DisableAppBar، پہلے سے غیر فعال) کو آن کر دیتا ہے تو یہ چھپ جاتا ہے۔
registerRightHandSidebarComponentدائیں جانب پینل۔ لوگ اس کی کنارے کو ڈریگ کرکے اس کا سائز تبدیل کر سکتے ہیں، اور اسے نئے ونڈو میں کھول سکتے ہیں۔ اگر ایپ ایک پروڈکٹ بھی ہو، تو پینل مکمل صفحے کے طور پر کھولیں کا آپشن پیش کرتا ہے۔ دیکھیں نئے ونڈو میں پینل۔
registerChannelHeaderIconچینل ہیڈر میں آئیکنز، کال بٹنز کے بعد؛ فونز پر ہیڈر کے مزید میو میں۔
registerCallButtonActionچینل ہیڈر کا کال بٹن؛ کئی پرووائڈرز کال کرنے کے دیگر طریقے میو کو شیئر کرتے ہیں۔
registerPostDropdownMenuActionپیغام کے پیغام کے اقدامات (⋯) مینیو، اس کے مزید اقدامات سب مینیو میں؛ نیز سلسلے کے پینل کے سلسلے کے اقدامات مینیو میں، مزید اقدامات کے تحت۔ Fusion ہر اقدام سے پہلے ایپ کی آئیکن کو سرمئی رنگ میں ڈرائے کرتی ہے: باندل شدہ ایپس کے لیے اپنی آئیکن، ورنہ ایپ کی وہ آئیکن جو ایپ ریل میں دکھاتی ہے، ورنہ ایک نیوٹرل آئیکن۔ اگر کسی عنصر میں اقدام کے متن کے آغاز پر کوئی متن نہ ہو (ایک ایسی آئیکن جو ایپ خود ڈرائے کرتی ہے)، تو وہ چھپا دیا جاتا ہے۔
registerPostDropdownSubMenuActionایک ہی مزید اقدامات سب مینیو میں، انفرادی اقدامات کے بعد، ایک ہیڈنگ والا گروپ۔ کوئی ایپ پیغام کے مینیو میں اپنی الگ اندراج نہیں پاتی۔
registerPostActionComponentمیسج ہاور ٹول بار، ⋯ بٹن سے پہلے۔
registerPostTypeComponent, registerPostMessageAttachmentComponent, registerPostHeaderComponent, registerPostWillRenderEmbedComponentمیسج خود: اس کا باڈی، اس کے متن کے نیچے، اس کے وقت کے بعد، اور لنک پری ویوز کی جگہ۔
registerChannelHeaderMenuActionچینل کا چینل کے اختیارات میو (سائیڈ بار میں چینل پر ⋯، یا رائٹ کلک)، پلگ آئیکن والے آئٹمز کے طور پر۔
registerMainMenuActionکمیونٹی میو (چینل لسٹ کے اوپر کمیونٹی کا نام)، مزید اقدامات کے تحت، ایپ کے لحاظ سے گروپ شدہ۔
registerSidebarBrowseOrAddChannelMenuActionکمیونٹی میو، چینل بنائیں اور زمرہ بنائیں کے بعد۔
registerFileUploadMethodکمپوزر کا + میو (پیغام میں شامل کریں)، فائل اپ لوڈ کریں کے بعد۔
registerPostEditorActionComponentکمپوزر کا فارمیٹنگ بار، جب فارمیٹنگ دکھائی جائے۔
registerAIActionMenuItemComponentکمپوزر کا AI مینیو۔
registerFileDropdownMenuAction, registerFilePreviewComponentفائل کا آپشنز مینیو، اور فائل پری ویو۔
registerUserSettingsپروفائل اور ترتیبات، پلگ انز ہیڈنگ کے تحت ہر ایپ کے لیے ایک ٹیب۔
registerChannelSettingsTabچینل کی ترتیبات ڈائیلاگ، ایپس ہیڈنگ کے تحت۔
registerPopoverUserAttributesComponent, registerPopoverUserActionsComponentپروفائل کارڈ، جو آپ کو نام یا ایواٹار پر کلک کرنے پر دکھائی دیتا ہے۔
registerLeftSidebarHeaderComponent, registerSidebarChannelLinkLabelComponent, registerChannelIconOverride, registerBottomTeamSidebarComponentکمیونٹی کے چینلز کی فہرست کا اوپری حصہ، چینل کے نام کے ساتھ، چینل کی آئیکن کے ساتھ، اور بائیں جانب کمیونٹی ریل کا نچلا حصہ۔
registerChannelIntro, registerChannelIntroButtonAction, registerChannelToastComponent, registerNewMessagesSeparatorActionComponent, registerChannelComposerBannerComponent, registerComposerPlaceholderکسی چینل کی تاریخ کا آغاز، پیغامات کی فہرست کا اوپری حصہ، غیر پڑھا لائن، کمپوزر کے اوپر، اور کمپوزر کا پلیس ہولڈر۔
registerChannelTypeOptionچینل بنائیں ڈائیلاگ کے چینل کے اقسام۔
registerSearchComponentsچینل ہیڈر کا تلاش خانہ: ایپ اسکوپس اس وقت ظاہر ہوتے ہیں جب یہ خالی ہو۔
registerUserGuideDropdownMenuActionAntimatter کے بارے میں (ایپ ریل کا نچلا حصہ)، مدد کے تحت۔
registerProductپروڈکٹ کے URL پر مکمل صفحات، جو Antimatter کے بارے میں میں مصنوعات کے تحت درج ہیں۔ پروڈکٹ صفحات کلاسیکی پیج فریم کو برقرار رکھتے ہیں، جس کا پروڈکٹ مینیو صرف اس وقت دکھتا ہے جب کوئی ایپ پروڈکٹ رجسٹر کرتی ہو یا اس میں اندراج شامل کرتی ہو۔ باندل شدہ Kanban اور Playbooks ایپس اب پروڈکٹس رجسٹر نہیں کرتیں: ان کے صفحات ان کے سائیڈ پینلز میں کھلتے ہیں۔
registerRootComponent, registerGlobalComponent, ہکس جیسے registerMessageWillBePostedHook, registerSlashCommandWillBePostedHook, registerMessageWillFormatHook, registerFilesWillUploadHook, registerDesktopNotificationHook, registerWebSocketEventHandler, registerReducer, registerTranslationsکلاسیک انٹرفیس کی طرح کام کریں۔
registerAdminConsolePlugin, registerAdminConsoleCustomSettingسسٹم کنسول، جو دونوں انٹرفیسز میں کلاسیک ہے۔

Fusion جو چیزیں ظاہر یا چلا نہیں کرتا

  • registerPostDropdownMenuComponent (پیغام کے مینیو میں ایک کمپوننٹ)، registerPostCardTypeComponent (پیغام کا کارڈ دائیں جانب پینل میں) اور registerProductSwitcherMenuItem Fusion کے مرکزی ویوز میں ظاہر نہیں ہوتے۔ پہلے کے بجائے registerPostDropdownMenuAction استعمال کریں۔
  • registerMessageWillBeUpdatedHook Fusion میں پیغام کے ترمیم کے وقت نہیں چلتا۔ ترمیمات کو سرور پر MessageWillBeUpdated ہک کے ذریعے چیک کریں۔
  • registerActionAfterChannelCreation صرف کلاسیک چینل تخلیق ڈائیلاگ سے چلتا ہے، جسے Fusion اپنے چینل بنائیں ڈائیلاگ میں مزید اختیارات… سے کھولتا ہے۔
  • ایپ بار کمپوننٹس ان کے supportedProductIds سے قطع نظر ظاہر ہوتے ہیں۔
  • registerNeedsTeamRoute اور registerCustomRoute سے آنے والے روٹس کلاسیک پیج فریم برقرار رکھتے ہیں، جیسے پروڈکٹس۔

ہکس جو صرف Antimatter میں ہیں

یہ رجسٹری طریقے Mattermost پر موجود نہیں ہیں۔ کال کرنے سے پہلے چیک کریں کہ طریقہ موجود ہے، تاکہ ایپ وہاں بھی کام کرے:

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');
}
طریقہیہ کیا شامل کرتا ہے
registerComposerMenuItem({text, icon, fusionIcon, action, shouldRender})پیغام باکس کے + مینیو میں ایک آئٹم، دونوں انٹرفیسز میں۔ action کو {channelId, rootId} ملتا ہے۔
registerEmojiPickerTab({id, label, icon, fusionIcon, order, component, shouldRender, replacesGifPicker})پیغام باکس کے ایموجی پکر کا ایک ٹیب، جیسے GIFs یا اسٹیکرز۔ Fusion میں، 10 سے کم order والے ٹیبز ایموجی ٹیب سے پہلے آتے ہیں۔ کمپوننٹ کو channelId، rootId، filter، onFilterChange، onSelectDone، insertText، isFusion اور، Fusion میں، pickerKit (نیچے دیکھیں) ملتا ہے۔
registerChannelViewPanel({matcher, component})چینل ہیڈر اور پیغامات کے درمیان ایک پینل، جن چینلز کے لیے matcher(state, channel) منتخب کرتا ہے۔ یہ پیغامات اور کمپوزر کو چھپا سکتا ہے (setMessagesVisible)، جیسا کہ وائس چینلز کرتے ہیں۔
registerSidebarChannelFooterComponent(component)سائیڈ بار میں چینل کے نیچے ایک قطار، جیسے اس کی کال میں موجود افراد۔ یہ channel وصول کرتا ہے۔
registerIntegrationsOption({title, description, fusionIcon, action, shouldRender})صرف Fusion: انضمامات صفحات پر ایک اندراج، کسٹم ایموجی کے ساتھ۔ GIF ایپ وہاں اپنے کسٹم GIF اور اسٹیکرز شامل کرتی ہے۔

ایموجی پکر میں ویوز شامل کریں اور ان کا انتظام کریں

Fusion میں، ایموجی پیکر کے ٹیب کو pickerKit پراپ ملتا ہے: یہ وہ کمپوننٹس ہیں جو ایموجی ٹیب اپنے add اور manage ویوز کے لیے استعمال کرتا ہے، تاکہ ٹیب کے ویوز ایک جیسے نظر آئیں اور پیکر کے اندر ہی رہیں۔ GIFs اور Memes ایپس اسے GIFs، اسٹیکرز اور میم ٹیمپلیٹس کو add اور manage کرنے کے لیے استعمال کرتی ہیں۔ اس میں version (1)، ہکس usePickerView اور useOnEscape، اور کمپوننٹس PickerViewButtons (سرچ باکس کے ساتھ + اور manage بٹنز)، PickerViewFrame (اپنی بیک اریو کے ساتھ ایک ویو)، PickerNotice، PickerField، PickerSearch، PickerDropZone اور PickerManageList شامل ہیں۔ Escape دبا کر کسی ویو سے ٹیب کے گرڈ پر واپس جاتے ہیں۔ چیک کریں کہ یہ پراپ موجود ہے: دیگر ہوسٹس اسے چھوڑ دیتے ہیں، اور اس صورت میں ٹیب اپنے ڈائیلاگز خود رکھتا ہے۔ ٹائپس webapp/fusion/src/types/store/plugins.ts (EmojiPickerTabProps) میں اور کمپوننٹس webapp/fusion/src/fusion/popovers/picker_views.tsx میں موجود ہیں۔

نئے ونڈو میں پینل

Fusion، registerRightHandSidebarComponent کے کمپوننٹ کو دو مزید پراپس دیتا ہے، تاکہ نئے ونڈو میں کھولیں پینل کو ایسی جگہ کھولے جہاں وہ پہلے تھا، نہ کہ ایپ کے ہوم پر:

  • setPanelState(state): اسے پینل کی جگہ بدلنے پر کال کریں، اپنے ایپ کے ذریعے تعریف کردہ ایک مختصر سٹرنگ کے ساتھ، جیسے 'note/<id>' یا 'board/<id>/card/<id>'، یا اپنے ہوم پر null۔ یہ ونڈو کے ایڈریس میں جاتا ہے، اس لیے اس میں کبھی کوئی راز نہ ڈالیں۔ 512 حروف سے طویل سٹیٹ، یا کنٹرول کاریکٹرز والا سٹیٹ، خارج کر دیا جاتا ہے۔
  • initialPanelState: نئے ونڈو میں، وہ سٹیٹ جو پینل کے پاس تھی، یا undefined۔ اسے غیر معتبر ان پٹ کے طور پر سمجھیں: سائنڈ ان صارف کے طور پر آئٹم کو دوبارہ fetch کریں، اور اگر وہ اسے کھول نہیں سکتا ہے تو ایپ کا ہوم یا not-found ویو دکھائیں۔

جب پینل بند ہو جائے یا کسی دوسری ایپ کا پینل اس کی جگہ لے لے تو سٹیٹ بھول جاتی ہے۔ کسی پینل کے ونڈو کو خود کھولنے کے لیے، popoutRhsPlugin (جو window.WebappUtils.popouts میں بھی موجود ہے) سٹیٹ کو اختیاری پانچویں آرگومنٹ کے طور پر لیتا ہے۔ Notes، Whiteboard، Todo، Kanban اور Playbooks اس کا استعمال کرتے ہیں۔

fusionIcon Fusion کے آئیکن سیٹ میں سے ایک آئیکن کا نام ہے (مثلاً poll، sticker، calendar یا image؛ دیکھیں webapp/fusion/src/fusion/components/icon)۔ Fusion اسے icon کی جگہ دکھاتا ہے، تاکہ یہ آئیٹم دوسروں کے مطابق ہو۔

ترتیبات

plugin.json میں settings_schema سسٹم کنسول › پلگ انز میں ایپ کا صفحہ بیان کرتا ہے:

"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."}
  ]
}

ترتیبات کی اقسام: bool، text، longtext، number، dropdown، radio، generated (ایک رینڈم سیکرٹ)، username، اور custom (جو ایک کمپوننٹ سے بنایا جاتا ہے جو ویب ایپ حصہ registerAdminConsoleCustomSetting کے ساتھ رجسٹر کرتا ہے)۔ ترتیبات کو sections میں گروپ کیا جا سکتا ہے۔

سرور کا حصہ انہیں ایک سٹرکٹ میں پڑھتا ہے جس کے فیلڈز کیز کے مطابق ہوتے ہیں:

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
}

ایڈمنز انہیں کنفیگریشن میں بھی سیٹ کر سکتے ہیں، PluginSettings.Plugins.<app id> کے تحت، چھوٹے حروف میں کیز کے ساتھ (دیکھیں ایڈمن گائیڈ)۔

ترجمے

Antimatter کو 37 زبانوں میں ترجمہ کیا گیا ہے، اور شامل ایپس بھی۔ ویب ایپ کا حصہ اسے اس طرح کرتا ہے:

  1. ہر سٹرنگ کو React Intl کے ساتھ لکھیں، ایک ID اور اس کے انگریزی متن کے ساتھ: <FormattedMessage id='polls.create' defaultMessage='Create a poll'/> یا defineMessages۔ IDs کو اپنی ایپ کے نام سے پیش کریں۔
  2. انگریزی سٹرنگز کو webapp/i18n/en.json میں نکالیں (شامل ایپس formatjs extract استعمال کرتی ہیں)۔
  3. اس کے ساتھ ہر زبان کے لیے ایک فائل شامل کریں، ایک ہی IDs کے ساتھ: fr.json، de.json، pt-BR.json، zh-CN.json…
  4. انہیں ویب ایپ کو دیں، جو صارف کی زبان پوچھتی ہے:
    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);

اگر کوئی سٹرنگ موجود نہ ہو تو اس کی انگریزی defaultMessage استعمال ہوتی ہے۔ ان سٹرنگز کے لیے جو سرور حصہ بھیجتا ہے (کمانڈ کے جوابات، بوٹ پیغامات)، pluginapi/i18n پیکج بنڈل میں شامل ترجمہ فائلز (مثلاً assets/i18n) لوڈ کرتا ہے اور ہر صارف کی زبان میں لوکلائزر فراہم کرتا ہے۔

بنائیں، انسٹال کریں اور ڈیبگ کریں

آپ کو Go اور Node.js (ایپ کے .nvmrc میں دی گئی ورژن) درکار ہیں۔ ایپ کے فولڈر میں:

کمانڈیہ کیا کرتا ہے
make distہر پلیٹ فارم کے لیے سرور حصہ اور ویب ایپ حصہ بناتا ہے، اور بنڈل کو dist/<app id>-<version>.tar.gz میں لکھتا ہے۔
make testGo اور JavaScript ٹیسٹ چلاتا ہے۔
make check-styleکوڈ کو لِنٹ کرتا ہے (golangci-lint, ESLint) اور TypeScript کی قسموں کی جانچ کرتا ہے۔
make deployبناتا ہے، پھر سرور پر بنڈل کو انسٹال اور فعال کرتا ہے۔
make watch, make deploy-from-watchپہلا ہر بار آپ کے سیو کرنے پر ویب ایپ حصہ دوبارہ بناتا ہے؛ دوسرا جو کچھ بنایا اسے بنڈل کر کے سرور پر انسٹال کرتا ہے۔
make enable, make disable, make resetسرور پر ایپ کو فعال، غیر فعال یا دوبارہ شروع کریں۔
make logs, make logs-watchسرور لاگ میں ایپ کی لائنز دکھائیں۔
make attachچل رہے سرور حصے کے ساتھ Delve ڈیبگر کو منسلک کرتا ہے (پہلے AM_DEBUG=1 کے ساتھ بنائیں)۔

make deploy اور دیگر سرور کمانڈز جب ایک مقامی موڈ سوکیٹ پاتے ہیں (/var/tmp/antimatter_local.socket، یا AM_LOCALSOCKETPATH) تو اسے استعمال کرتے ہیں: انہیں مقامی موڈ آن ہو کر سرور کی مشین پر چلائیں۔ ورنہ وہ MM_SERVICESETTINGS_SITEURL سے دیے گئے سرور پر AM_ADMIN_TOKEN، یا AM_ADMIN_USERNAME اور AM_ADMIN_PASSWORD کے ساتھ سائن ان کرتے ہیں۔ بلڈ ٹولز ابھی سائٹ URL کے لیے AM_ نام نہیں پڑھتے۔

بنڈل کو دستی طور پر انسٹال کریں

  • سسٹم ایڈمن AM_PLUGINSETTINGS_ENABLEUPLOADS=true کے ساتھ اپ لوڈز کی اجازت دیتا ہے (ڈیفالٹ طور پر بند؛ سسٹم کنسول میں کوئی سوئچ نہیں ہے)۔
  • پھر سسٹم کنسول › پلگ انز › پلگ ان مینجمنٹ › پلگ ان اپ لوڈ کریں، یا amctl plugin add weather.tar.gz کے بعد amctl plugin enable com.example.weather۔
  • اگر سروسرور پر پلگ ان سائنچر کو لازمی قرار دیں آن ہے، تو یہ صرف ان باندلز کو قبول کرتا ہے جو اس کے اعتماد کے ساتھ سائن شدہ ہوں؛ دیکھیں دیگر ایپس کی تنصیب۔
ڈویلپمنٹ سرور پر تیز دہائیوں کے لیے، سرور پر AM_SERVICESETTINGS_ENABLEDEVELOPER=true سیٹ کریں: اس صورت میں غلطیاں اپنے تفصیلی معلومات کے ساتھ آتی ہیں۔ بنڈل شدہ ایپس کے Makefiles صرف تب آپ کے پلیٹ فارم کے لیے سرور حصہ بناتے ہیں جب آپ کے شیل میں MM_SERVICESETTINGS_ENABLEDEVELOPER سیٹ ہو۔