diff --git a/js/src/admin/components/AddExtensionModal.tsx b/js/src/admin/components/AddExtensionModal.tsx new file mode 100644 index 000000000..770793f71 --- /dev/null +++ b/js/src/admin/components/AddExtensionModal.tsx @@ -0,0 +1,24 @@ +import app from '../app'; +import Modal from '../../common/components/Modal'; + +export default class AddExtensionModal extends Modal { + className() { + return 'AddExtensionModal Modal--small'; + } + + title() { + return app.translator.trans('core.admin.add_extension.title'); + } + + content() { + return ( +
+

{app.translator.trans('core.admin.add_extension.temporary_text')}

+

+ {app.translator.trans('core.admin.add_extension.install_text', { a: })} +

+

{app.translator.trans('core.admin.add_extension.developer_text', { a: })}

+
+ ); + } +} diff --git a/js/src/admin/components/AdminNav.tsx b/js/src/admin/components/AdminNav.tsx index badf2b4d5..3f0309798 100644 --- a/js/src/admin/components/AdminNav.tsx +++ b/js/src/admin/components/AdminNav.tsx @@ -70,12 +70,15 @@ export default class AdminNav extends Component { }) ); - // items.add('extensions', AdminLinkButton.component({ - // href: app.route('extensions'), - // icon: 'fas fa-puzzle-piece', - // children: app.translator.trans('core.admin.nav.extensions_button'), - // description: app.translator.trans('core.admin.nav.extensions_text') - // })); + items.add( + 'extensions', + AdminLinkButton.component({ + href: app.route('extensions'), + icon: 'fas fa-puzzle-piece', + children: app.translator.trans('core.admin.nav.extensions_button'), + description: app.translator.trans('core.admin.nav.extensions_text'), + }) + ); return items; } diff --git a/js/src/admin/components/ExtensionsPage.tsx b/js/src/admin/components/ExtensionsPage.tsx new file mode 100644 index 000000000..c990e179d --- /dev/null +++ b/js/src/admin/components/ExtensionsPage.tsx @@ -0,0 +1,130 @@ +import app from '../app'; + +import Page from './Page'; +import Button from '../../common/components/Button'; +import Dropdown from '../../common/components/Dropdown'; +import AddExtensionModal from './AddExtensionModal'; +import LoadingModal from './LoadingModal'; +import ItemList from '../../common/utils/ItemList'; +import icon from '../../common/helpers/icon'; + +export default class ExtensionsPage extends Page { + view() { + return ( +
+
+
+ {Button.component({ + children: app.translator.trans('core.admin.extensions.add_button'), + icon: 'fas fa-plus', + className: 'Button Button--primary', + onclick: () => app.modal.show(AddExtensionModal), + })} +
+
+ +
+
+
    + {Object.keys(app.data.extensions).map((id) => { + const extension = app.data.extensions[id]; + const controls = this.controlItems(extension.id).toArray(); + + return ( +
  • +
    + + {extension.icon ? icon(extension.icon.name) : ''} + + {controls.length ? ( + + {controls} + + ) : ( + '' + )} +
    + +
    {extension.version}
    +
    {extension.description}
    +
    +
    +
  • + ); + })} +
+
+
+
+ ); + } + + controlItems(name) { + const items = new ItemList(); + const enabled = this.isEnabled(name); + + if (app.extensionSettings[name]) { + items.add( + 'settings', + Button.component({ + icon: 'fas fa-cog', + children: app.translator.trans('core.admin.extensions.settings_button'), + onclick: app.extensionSettings[name], + }) + ); + } + + if (!enabled) { + items.add( + 'uninstall', + Button.component({ + icon: 'far fa-trash-alt', + children: app.translator.trans('core.admin.extensions.uninstall_button'), + onclick: () => { + app.request({ + url: app.forum.attribute('apiUrl') + '/extensions/' + name, + method: 'DELETE', + }).then(() => window.location.reload()); + + app.modal.show(LoadingModal); + }, + }) + ); + } + + return items; + } + + isEnabled(name) { + const enabled = JSON.parse(app.data.settings.extensions_enabled); + + return enabled.indexOf(name) !== -1; + } + + toggle(id) { + const enabled = this.isEnabled(id); + + app.request({ + url: app.forum.attribute('apiUrl') + '/extensions/' + id, + method: 'PATCH', + body: { enabled: !enabled }, + }).then(() => { + if (!enabled) localStorage.setItem('enabledExtension', id); + window.location.reload(); + }); + + app.modal.show(LoadingModal); + } +} diff --git a/js/src/admin/routes.ts b/js/src/admin/routes.ts index a6fa8c869..0269787c2 100644 --- a/js/src/admin/routes.ts +++ b/js/src/admin/routes.ts @@ -3,6 +3,7 @@ import DashboardPage from './components/DashboardPage'; import MailPage from './components/MailPage'; import PermissionsPage from './components/PermissionsPage'; import AppearancePage from './components/AppearancePage'; +import ExtensionsPage from './components/ExtensionsPage'; export default (app) => { app.routes = { @@ -11,5 +12,6 @@ export default (app) => { mail: { path: '/mail', component: MailPage }, permissions: { path: '/permissions', component: PermissionsPage }, appearance: { path: '/appearance', component: AppearancePage }, + extensions: { path: '/extensions', component: ExtensionsPage }, }; };