Ana içeriğe geç
Version: 1.x

Yönetici Gösterge Tablosu

Beta 15, tamamen yeniden tasarlanmış bir yönetici paneli ve frontend API'sini tanıttı. Uzantınıza ayar veya izin eklemek artık her zamankinden daha kolay.

Beta 15'ten önce, uzantı ayarları ya bir SettingsModal'a ekleniyordu ya da daha karmaşık ayarlar için yeni bir sayfa ekleniyordu. Artık her uzantının bilgileri, ayarları ve uzantının kendi izinlerini içeren bir sayfası var.

Ayarları kolayca kaydedebilir, temel Uzantı Sayfası genişletebilir veya kendi tamamen özel sayfanızı sağlayabilirsiniz.

Uzantı Veri API'si

Bu yeni API, çok az kod satırıyla uzantınıza ayarlar eklemenizi sağlar.

Telling the API about your extension

Before you can register anything, you need to tell ExtensionData what extension it is about to get data for.

Simply run the for function on app.extensionData passing in the id of your extension. To find you extension id, take the composer name and replace any slashes with dashes (example: 'fof/merge-discussions' becomes 'fof-merge-discussions'). Extensions with the flarum- and flarum-ext- will omit those from the name (example: 'webbinaro/flarum-calendar' becomes 'webbinaro-calendar').

For the following example, we will use the fictitious extension 'acme/interstellar':


app.initializers.add('interstellar', function(app) {

app.extensionData
.for('acme-interstellar')
});

Once that is done, you can begin adding settings and permissions.

Note

All registration functions on ExtensionData are chainable, meaning you can call them one after another without running for again.

Registering Settings

Adding settings fields in this way is recommended for simple items. As a rule of thumb, if you only need to store things in the settings table, this should be enough for you.

To add a field, call the registerSetting function after for on app.extensionData and pass a 'setting object' as the first argument. Behind the scenes ExtensionData actually turns your settings into an ItemList, you can pass a priority number as the second argument.

Here's an example with a switch (boolean) item:


app.initializers.add('interstellar', function(app) {

app.extensionData
.for('acme-interstellar')
.registerSetting(
{
setting: 'acme-interstellar.coordinates', // This is the key the settings will be saved under in the settings table in the database.
label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // The label to be shown letting the admin know what the setting does.
help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Optional help text where a longer explanation of the setting can go.
type: 'boolean', // What type of setting this is, valid options are: boolean, text (or any other <input> tag type), and select.
},
30 // Optional: Priority
)
});

If you use type: 'select' the setting object looks a little bit different:

{
setting: 'acme-interstellar.fuel_type',
label: app.translator.trans('acme-interstellar.admin.fuel_type_label'),
type: 'select',
options: {
'LOH': 'Liquid Fuel', // The key in this object is what the setting will be stored as in the database, the value is the label the admin will see (remember to use translations if they make sense in your context).
'RDX': 'Solid Fuel',
},
default: 'LOH',
}

Also, note that additional items in the setting object will be used as component attrs. This can be used for placeholders, min/max restrictions, etc:

{
setting: 'acme-interstellar.crew_count',
label: app.translator.trans('acme-interstellar.admin.crew_count_label'),
type: 'number',
min: 1,
max: 10
}

If you want to add something to the settings like some extra text or a more complicated input, you can also pass a callback as the first argument that returns JSX. This callback will be executed in the context of ExtensionPage and setting values will not be automatically serialized.


app.initializers.add('interstellar', function(app) {

app.extensionData
.for('acme-interstellar')
.registerSetting(function () {
if (app.session.user.username() === 'RocketMan') {

return (
<div className="Form-group">
<h1> {app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')} </h1>
<label className="checkbox">
<input type="checkbox" bidi={this.setting('acme-interstellar.rocket_man_setting')}/>
{app.translator.trans('acme-interstellar.admin.rocket_man_setting_label')}
</label>
</div>
);
}
})
});

Registering Permissions

New in beta 15, permissions can now be found in 2 places. Now, you can view each extension's individual permissions on their page. All permissions can still be found on the permissions page.

In order for that to happen, permissions must be registered with ExtensionData. This is done in a similar way to settings, call registerPermission.

Arguments:

  • Permission object
  • What type of permission - see PermissionGrid's functions for types (remove items from the name)
  • ItemList priority

Back to our favorite rocket extension:

app.initializers.add('interstellar', function(app) {

app.extensionData
.for('acme-interstellar')
.registerPermission(
{
icon: 'fas fa-rocket', // Font-Awesome Icon
label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Permission Label
permission: 'discussion.rocket_fly', // Actual permission name stored in database (and used when checking permission).
tagScoped: true, // Whether it be possible to apply this permission on tags, not just globally. Explained in the next paragraph.
},
'start', // Category permission will be added to on the grid
95 // Optional: Priority
);
});

If your extension interacts with the tags extension (which is fairly common), you might want a permission to be tag scopable (i.e. applied on the tag level, not just globally). You can do this by including a tagScoped attribute, as seen above. Permissions starting with discussion. will automatically be tag scoped unless tagScoped: false is indicated.

To learn more about Flarum permissions, see the relevant docs.

Chaining Reminder

Remember these functions can all be chained like:

app.extensionData
.for('acme-interstellar')
.registerSetting(...)
.registerSetting(...)
.registerPermission(...)
.registerPermission(...);

Extending/Overriding the Default Page

Sometimes you have more complicated settings that mess with relationships, or just want the page to look completely different. In this case, you will need to tell ExtensionData that you want to provide your own page. Note that buildSettingComponent, the util used to register settings by providing a descriptive object, is available as a method on ExtensionPage (extending from AdminPage, which is a generic base for all admin pages with some util methods).

Create a new class that extends the Page or ExtensionPage component:

import ExtensionPage from 'flarum/admin/components/ExtensionPage';

export default class StarPage extends ExtensionPage {
content() {
return (
<h1>Hello from the settings section!</h1>
)
}
}

Then, simply run registerPage:


import StarPage from './components/StarPage';

app.initializers.add('interstellar', function(app) {

app.extensionData
.for('acme-interstellar')
.registerPage(StarPage);
});

This page will be shown instead of the default.

You can extend the ExtensionPage or extend the base Page and design your own!

Composer.json Metadata

In beta 15, extension pages make room for extra info which is pulled from extensions' composer.json.

For more information, see the composer.json schema.

DescriptionWhere in composer.json
discuss.flarum.org discussion link"forum" key inside "support"
Documentation"docs" key inside "support"
Support (email)"email" key inside "support"
Website"homepage" key
Donate"funding" key block (Note: Only the first link will be used)
Source"source" key inside "support"