mirror of
https://github.com/flarum/framework.git
synced 2024-11-29 04:33:47 +08:00
Extension permission typings, fix glitch with extension permissions grid
This commit is contained in:
parent
b14f7d9963
commit
5a26dd8c4b
|
@ -1,26 +1,36 @@
|
||||||
import app from '../../admin/app';
|
import app from '../../admin/app';
|
||||||
import PermissionGrid from './PermissionGrid';
|
import PermissionGrid, { PermissionGridEntry } from './PermissionGrid';
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
import ItemList from '../../common/utils/ItemList';
|
import ItemList from '../../common/utils/ItemList';
|
||||||
|
import Mithril from 'mithril';
|
||||||
|
|
||||||
export default class ExtensionPermissionGrid extends PermissionGrid {
|
export interface IExtensionPermissionGridAttrs {
|
||||||
oninit(vnode) {
|
extensionId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ExtensionPermissionGrid<
|
||||||
|
CustomAttrs extends IExtensionPermissionGridAttrs = IExtensionPermissionGridAttrs
|
||||||
|
> extends PermissionGrid<CustomAttrs> {
|
||||||
|
protected extensionId!: string;
|
||||||
|
|
||||||
|
oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||||
super.oninit(vnode);
|
super.oninit(vnode);
|
||||||
|
|
||||||
this.extensionId = this.attrs.extensionId;
|
this.extensionId = this.attrs.extensionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionItems() {
|
permissionItems() {
|
||||||
const permissionCategories = super.permissionItems();
|
const items = new ItemList<{ label: Mithril.Children; children: PermissionGridEntry[] }>();
|
||||||
|
|
||||||
permissionCategories.items = Object.entries(permissionCategories.items)
|
super
|
||||||
.filter(([category, info]) => info.content.children.length > 0)
|
.permissionItems()
|
||||||
.reduce((obj, [category, info]) => {
|
.toArray()
|
||||||
obj[category] = info;
|
.filter((item) => item.children.length > 0)
|
||||||
return obj;
|
.forEach((item) => {
|
||||||
}, {});
|
items.add(item.itemName, item);
|
||||||
|
});
|
||||||
|
|
||||||
return permissionCategories;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewItems() {
|
viewItems() {
|
|
@ -1,17 +1,49 @@
|
||||||
import app from '../../admin/app';
|
import app from '../../admin/app';
|
||||||
import Component from '../../common/Component';
|
import Component, { ComponentAttrs } from '../../common/Component';
|
||||||
import PermissionDropdown from './PermissionDropdown';
|
import PermissionDropdown from './PermissionDropdown';
|
||||||
import SettingDropdown from './SettingDropdown';
|
import SettingDropdown from './SettingDropdown';
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
import ItemList from '../../common/utils/ItemList';
|
import ItemList from '../../common/utils/ItemList';
|
||||||
import icon from '../../common/helpers/icon';
|
import icon from '../../common/helpers/icon';
|
||||||
|
import type Mithril from 'mithril';
|
||||||
|
|
||||||
export default class PermissionGrid extends Component {
|
export interface PermissionConfig {
|
||||||
view() {
|
permission: string;
|
||||||
|
icon: string;
|
||||||
|
label: Mithril.Children;
|
||||||
|
allowGuest?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PermissionSetting {
|
||||||
|
setting: () => Mithril.Children;
|
||||||
|
icon: string;
|
||||||
|
label: Mithril.Children;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PermissionGridEntry = PermissionConfig | PermissionSetting;
|
||||||
|
|
||||||
|
export type PermissionType = 'view' | 'start' | 'reply' | 'moderate';
|
||||||
|
|
||||||
|
export interface ScopeItem {
|
||||||
|
label: Mithril.Children;
|
||||||
|
render: (permission: PermissionGridEntry) => Mithril.Children;
|
||||||
|
onremove?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPermissionGridAttrs extends ComponentAttrs {}
|
||||||
|
|
||||||
|
export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = IPermissionGridAttrs> extends Component<CustomAttrs> {
|
||||||
|
view(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||||
const scopes = this.scopeItems().toArray();
|
const scopes = this.scopeItems().toArray();
|
||||||
|
|
||||||
const permissionCells = (permission) => {
|
const permissionCells = (permission: PermissionGridEntry | { children: PermissionGridEntry[] }) => {
|
||||||
return scopes.map((scope) => <td>{scope.render(permission)}</td>);
|
return scopes.map((scope) => {
|
||||||
|
if ('children' in permission) {
|
||||||
|
return <td></td>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.render(permission);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -56,7 +88,10 @@ export default class PermissionGrid extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionItems() {
|
permissionItems() {
|
||||||
const items = new ItemList();
|
const items = new ItemList<{
|
||||||
|
label: Mithril.Children;
|
||||||
|
children: PermissionGridEntry[];
|
||||||
|
}>();
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
'view',
|
'view',
|
||||||
|
@ -98,7 +133,7 @@ export default class PermissionGrid extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewItems() {
|
viewItems() {
|
||||||
const items = new ItemList();
|
const items = new ItemList<PermissionGridEntry>();
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
'viewForum',
|
'viewForum',
|
||||||
|
@ -162,7 +197,7 @@ export default class PermissionGrid extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
startItems() {
|
startItems() {
|
||||||
const items = new ItemList();
|
const items = new ItemList<PermissionGridEntry>();
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
'start',
|
'start',
|
||||||
|
@ -205,7 +240,7 @@ export default class PermissionGrid extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
replyItems() {
|
replyItems() {
|
||||||
const items = new ItemList();
|
const items = new ItemList<PermissionGridEntry>();
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
'reply',
|
'reply',
|
||||||
|
@ -247,7 +282,7 @@ export default class PermissionGrid extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
moderateItems() {
|
moderateItems() {
|
||||||
const items = new ItemList();
|
const items = new ItemList<PermissionGridEntry>();
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
'viewIpsPosts',
|
'viewIpsPosts',
|
||||||
|
@ -365,16 +400,16 @@ export default class PermissionGrid extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
scopeItems() {
|
scopeItems() {
|
||||||
const items = new ItemList();
|
const items = new ItemList<ScopeItem>();
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
'global',
|
'global',
|
||||||
{
|
{
|
||||||
label: app.translator.trans('core.admin.permissions.global_heading'),
|
label: app.translator.trans('core.admin.permissions.global_heading'),
|
||||||
render: (item) => {
|
render: (item: PermissionGridEntry) => {
|
||||||
if (item.setting) {
|
if ('setting' in item) {
|
||||||
return item.setting();
|
return item.setting();
|
||||||
} else if (item.permission) {
|
} else if ('permission' in item) {
|
||||||
return PermissionDropdown.component({
|
return PermissionDropdown.component({
|
||||||
permission: item.permission,
|
permission: item.permission,
|
||||||
allowGuest: item.allowGuest,
|
allowGuest: item.allowGuest,
|
|
@ -13,7 +13,7 @@ export default class ExtensionPageResolver<
|
||||||
static extension: string | null = null;
|
static extension: string | null = null;
|
||||||
|
|
||||||
onmatch(args: Attrs & RouteArgs, requestedPath: string, route: string) {
|
onmatch(args: Attrs & RouteArgs, requestedPath: string, route: string) {
|
||||||
const extensionPage = app.extensionData.getPage(args.id);
|
const extensionPage = app.extensionData.getPage<Attrs>(args.id);
|
||||||
|
|
||||||
if (extensionPage) {
|
if (extensionPage) {
|
||||||
return extensionPage;
|
return extensionPage;
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
import ItemList from '../../common/utils/ItemList';
|
|
||||||
|
|
||||||
export default class ExtensionData {
|
|
||||||
constructor() {
|
|
||||||
this.data = {};
|
|
||||||
this.currentExtension = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function simply takes the extension id
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* app.extensionData.load('flarum-tags')
|
|
||||||
*
|
|
||||||
* flarum/flags -> flarum-flags | acme/extension -> acme-extension
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
*/
|
|
||||||
for(extension) {
|
|
||||||
this.currentExtension = extension;
|
|
||||||
this.data[extension] = this.data[extension] || {};
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function registers your settings with Flarum
|
|
||||||
*
|
|
||||||
* It takes either a settings object or a callback.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* .registerSetting({
|
|
||||||
* setting: 'flarum-flags.guidelines_url',
|
|
||||||
* type: 'text', // This will be inputted into the input tag for the setting (text/number/etc)
|
|
||||||
* label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')
|
|
||||||
* }, 15) // priority is optional (ItemList)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param content
|
|
||||||
* @param priority
|
|
||||||
* @returns {ExtensionData}
|
|
||||||
*/
|
|
||||||
registerSetting(content, priority = 0) {
|
|
||||||
this.data[this.currentExtension].settings = this.data[this.currentExtension].settings || new ItemList();
|
|
||||||
|
|
||||||
// Callbacks can be passed in instead of settings to display custom content.
|
|
||||||
// By default, they will be added with the `null` key, since they don't have a `.setting` attr.
|
|
||||||
// To support multiple such items for one extension, we assign a random ID.
|
|
||||||
// 36 is arbitrary length, but makes collisions very unlikely.
|
|
||||||
if (typeof content === 'function') {
|
|
||||||
content.setting = Math.random().toString(36);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data[this.currentExtension].settings.add(content.setting, content, priority);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function registers your permission with Flarum
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* .registerPermission('permissions', {
|
|
||||||
* icon: 'fas fa-flag',
|
|
||||||
* label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),
|
|
||||||
* permission: 'discussion.viewFlags'
|
|
||||||
* }, 'moderate', 65)
|
|
||||||
*
|
|
||||||
* @param content
|
|
||||||
* @param permissionType
|
|
||||||
* @param priority
|
|
||||||
* @returns {ExtensionData}
|
|
||||||
*/
|
|
||||||
registerPermission(content, permissionType = null, priority = 0) {
|
|
||||||
this.data[this.currentExtension].permissions = this.data[this.currentExtension].permissions || {};
|
|
||||||
|
|
||||||
if (!this.data[this.currentExtension].permissions[permissionType]) {
|
|
||||||
this.data[this.currentExtension].permissions[permissionType] = new ItemList();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data[this.currentExtension].permissions[permissionType].add(content.permission, content, priority);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the default extension page with a custom component.
|
|
||||||
* This component would typically extend ExtensionPage
|
|
||||||
*
|
|
||||||
* @param component
|
|
||||||
* @returns {ExtensionData}
|
|
||||||
*/
|
|
||||||
registerPage(component) {
|
|
||||||
this.data[this.currentExtension].page = component;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an extension's registered settings
|
|
||||||
*
|
|
||||||
* @param extensionId
|
|
||||||
* @returns {boolean|*}
|
|
||||||
*/
|
|
||||||
getSettings(extensionId) {
|
|
||||||
if (this.data[extensionId] && this.data[extensionId].settings) {
|
|
||||||
return this.data[extensionId].settings.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Get an ItemList of all extensions' registered permissions
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
* @param type
|
|
||||||
* @returns {ItemList}
|
|
||||||
*/
|
|
||||||
getAllExtensionPermissions(type) {
|
|
||||||
const items = new ItemList();
|
|
||||||
|
|
||||||
Object.keys(this.data).map((extension) => {
|
|
||||||
if (this.extensionHasPermissions(extension) && this.data[extension].permissions[type]) {
|
|
||||||
items.merge(this.data[extension].permissions[type]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a singular extension's registered permissions
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
* @param type
|
|
||||||
* @returns {boolean|*}
|
|
||||||
*/
|
|
||||||
getExtensionPermissions(extension, type) {
|
|
||||||
if (this.extensionHasPermissions(extension) && this.data[extension].permissions[type]) {
|
|
||||||
return this.data[extension].permissions[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ItemList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether a given extension has registered permissions.
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
extensionHasPermissions(extension) {
|
|
||||||
if (this.data[extension] && this.data[extension].permissions) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an extension's custom page component if it exists.
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
* @returns {boolean|*}
|
|
||||||
*/
|
|
||||||
getPage(extension) {
|
|
||||||
if (this.data[extension]) {
|
|
||||||
return this.data[extension].page;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
186
framework/core/js/src/admin/utils/ExtensionData.ts
Normal file
186
framework/core/js/src/admin/utils/ExtensionData.ts
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
import type Mithril from 'mithril';
|
||||||
|
import ItemList from '../../common/utils/ItemList';
|
||||||
|
import { SettingsComponentOptions } from '../components/AdminPage';
|
||||||
|
import ExtensionPage, { ExtensionPageAttrs } from '../components/ExtensionPage';
|
||||||
|
import { PermissionConfig, PermissionType } from '../components/PermissionGrid';
|
||||||
|
|
||||||
|
type SettingConfigInput = SettingsComponentOptions | (() => Mithril.Children);
|
||||||
|
|
||||||
|
type SettingConfigInternal = SettingsComponentOptions | ((() => Mithril.Children) & { setting: string });
|
||||||
|
|
||||||
|
export type CustomExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs> = new () => ExtensionPage<Attrs>;
|
||||||
|
|
||||||
|
type ExtensionConfig = {
|
||||||
|
settings?: ItemList<SettingConfigInternal>;
|
||||||
|
permissions?: {
|
||||||
|
view?: ItemList<PermissionConfig>;
|
||||||
|
start?: ItemList<PermissionConfig>;
|
||||||
|
reply?: ItemList<PermissionConfig>;
|
||||||
|
moderate?: ItemList<PermissionConfig>;
|
||||||
|
};
|
||||||
|
page?: CustomExtensionPage;
|
||||||
|
};
|
||||||
|
|
||||||
|
type InnerDataNoActiveExtension = {
|
||||||
|
currentExtension: null;
|
||||||
|
data: {
|
||||||
|
[key: string]: ExtensionConfig | undefined;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type InnerDataActiveExtension = {
|
||||||
|
currentExtension: string;
|
||||||
|
data: {
|
||||||
|
[key: string]: ExtensionConfig;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const noActiveExtensionErrorMessage = 'You must select an active extension via `.for()` before using extensionData.';
|
||||||
|
|
||||||
|
export default class ExtensionData {
|
||||||
|
protected state: InnerDataActiveExtension | InnerDataNoActiveExtension = {
|
||||||
|
currentExtension: null,
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function simply takes the extension id
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* app.extensionData.for('flarum-tags')
|
||||||
|
*
|
||||||
|
* flarum/flags -> flarum-flags | acme/extension -> acme-extension
|
||||||
|
*/
|
||||||
|
for(extension: string) {
|
||||||
|
this.state.currentExtension = extension;
|
||||||
|
this.state.data[extension] = this.state.data[extension] || {};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function registers your settings with Flarum
|
||||||
|
*
|
||||||
|
* It takes either a settings object or a callback.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* .registerSetting({
|
||||||
|
* setting: 'flarum-flags.guidelines_url',
|
||||||
|
* type: 'text', // This will be inputted into the input tag for the setting (text/number/etc)
|
||||||
|
* label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')
|
||||||
|
* }, 15) // priority is optional (ItemList)
|
||||||
|
*/
|
||||||
|
registerSetting(content: SettingConfigInput, priority = 0): this {
|
||||||
|
if (this.state.currentExtension === null) {
|
||||||
|
throw new Error(noActiveExtensionErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tmpContent = content as SettingConfigInternal;
|
||||||
|
|
||||||
|
// Callbacks can be passed in instead of settings to display custom content.
|
||||||
|
// By default, they will be added with the `null` key, since they don't have a `.setting` attr.
|
||||||
|
// To support multiple such items for one extension, we assign a random ID.
|
||||||
|
// 36 is arbitrary length, but makes collisions very unlikely.
|
||||||
|
if (tmpContent instanceof Function) {
|
||||||
|
tmpContent.setting = Math.random().toString(36);
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = this.state.data[this.state.currentExtension].settings || new ItemList();
|
||||||
|
settings.add(tmpContent.setting, tmpContent, priority);
|
||||||
|
|
||||||
|
this.state.data[this.state.currentExtension].settings = settings;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function registers your permission with Flarum
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* .registerPermission('permissions', {
|
||||||
|
* icon: 'fas fa-flag',
|
||||||
|
* label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),
|
||||||
|
* permission: 'discussion.viewFlags'
|
||||||
|
* }, 'moderate', 65)
|
||||||
|
*/
|
||||||
|
registerPermission(content: PermissionConfig, permissionType: PermissionType, priority = 0): this {
|
||||||
|
if (this.state.currentExtension === null) {
|
||||||
|
throw new Error(noActiveExtensionErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissions = this.state.data[this.state.currentExtension].permissions || {};
|
||||||
|
|
||||||
|
const permissionsForType = permissions[permissionType] || new ItemList();
|
||||||
|
|
||||||
|
permissionsForType.add(content.permission, content, priority);
|
||||||
|
|
||||||
|
this.state.data[this.state.currentExtension].permissions = { ...permissions, [permissionType]: permissionsForType };
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the default extension page with a custom component.
|
||||||
|
* This component would typically extend ExtensionPage
|
||||||
|
*/
|
||||||
|
registerPage(component: CustomExtensionPage): this {
|
||||||
|
if (this.state.currentExtension === null) {
|
||||||
|
throw new Error(noActiveExtensionErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.data[this.state.currentExtension].page = component;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an extension's registered settings
|
||||||
|
*/
|
||||||
|
getSettings(extensionId: string): SettingConfigInternal[] | undefined {
|
||||||
|
return this.state.data[extensionId]?.settings?.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an ItemList of all extensions' registered permissions
|
||||||
|
*/
|
||||||
|
getAllExtensionPermissions(type: PermissionType): ItemList<PermissionConfig> {
|
||||||
|
const items = new ItemList<PermissionConfig>();
|
||||||
|
|
||||||
|
Object.keys(this.state.data).map((extension) => {
|
||||||
|
const extPerms = this.state.data[extension]?.permissions?.[type];
|
||||||
|
if (this.extensionHasPermissions(extension) && extPerms !== undefined) {
|
||||||
|
items.merge(extPerms);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a singular extension's registered permissions
|
||||||
|
*/
|
||||||
|
getExtensionPermissions(extension: string, type: PermissionType): ItemList<PermissionConfig> {
|
||||||
|
const extPerms = this.state.data[extension]?.permissions?.[type];
|
||||||
|
if (this.extensionHasPermissions(extension) && extPerms != null) {
|
||||||
|
return extPerms;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ItemList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a given extension has registered permissions.
|
||||||
|
*/
|
||||||
|
extensionHasPermissions(extension: string) {
|
||||||
|
return this.state.data[extension]?.permissions !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an extension's custom page component if it exists.
|
||||||
|
*/
|
||||||
|
getPage<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs>(extension: string): CustomExtensionPage<Attrs> | undefined {
|
||||||
|
return this.state.data[extension]?.page as CustomExtensionPage<Attrs> | undefined;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user