Skip to content

Commit

Permalink
Extract from flamarkt/core
Browse files Browse the repository at this point in the history
  • Loading branch information
clarkwinkelmann committed Mar 28, 2022
0 parents commit 4f3204b
Show file tree
Hide file tree
Showing 104 changed files with 5,821 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
[*.md]
indent_size = 2
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
js/src export-ignore
.git* export-ignore

js/dist/*.js -diff
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
vendor
composer.lock
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Clark Winkelmann

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Backoffice

An alternative admin panel frontend for extensions.

Things this extension provides:

- `composer.json` parameters:
- `extra.flamarkt-backoffice.settingsInBackoffice`: whether to redirect admin to backoffice for settings
- `extra.flamarkt-backoffice.showInBackoffice`: whether to show extension in the extension list of backoffice
- `extra.flamarkt-backoffice.hideFromAdmin`: whether to hide extension from admin list of extensions
- Global `backoffice` gate to configure base access to the backoffice.
- Patch for https://github.com/flarum/framework/issues/2876 (now fixed).
- Verbatim relationships.
- `common/utils/KeyboardNavigatable`: same as Flarum but exported.
- `common/states/AbstractListState`: an alternative to Flarum's [PaginatedListState](https://github.com/flarum/framework/blob/main/framework/core/js/src/common/states/PaginatedListState.ts).
- `common/pages/AbstractShowPage`: a re-usable page component with pre-build logic for loading single models
- `common/components/AbstractRelationshipSelect`: re-usable select input.
- `common/components/AbstractSortDropdown`: re-usable component to create sort dropdowns.
- `common/components/ActiveLinkButton`: alternative to Flarum's `LinkButton` with ability to configure which routes will make the button `active` state.
- `common/components/Sortable`: a Mithril implementation of a re-orderable list.
- `common/components/SortableHandle`: to be used with `Sortable`.
- `common/components/UserRelationshipSelect`: implementation of `AbstractRelationshipSelect` for user model.
- `backoffice/states/UserListState`
- `backoffice/resolvers/ExtensionPageResolver`: same as Flarum but exported.
- `backoffice/pages/DashboardPage`
- `backoffice/pages/UserIndexPage`
- `backoffice/pages/UserShowPage`
- `backoffice/components/AbstractList`: re-usable component for index pages in backoffice.
- `backoffice/components/BackofficeNav`: same usage as Flarum's `AdminNav`.
- `backoffice/components/HeaderPrimary`: same usage as Flarum's `HeaderPrimary`.
- `backoffice/components/HeaderSecondary`: same usage as Flarum's `HeaderSecondary`.
- `backoffice/components/PermanentDeleteButton`: re-usable button with built-in API request.
- `backoffice/components/SoftDeleteButton`: re-usable delete/restore button with built-in API request.
- `backoffice/components/SubmitButton`: re-usable button with built-in translations.
- `backoffice/components/UserList`: implementation of `AbstractList` for `UserIndexPage`.
- `backoffice/components/UserSortDropdown`: implementation of `AbstractSortDropdown` for user model.
- Optional migrations through `when` callback in migration definition.

This package is implemented as an extension because it's the most reliable way to make sure all the logic runs only once and before any of the extensions that will use it.

More documentation will be published once out of beta.
50 changes: 50 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "flamarkt/backoffice",
"description": "Starting point for Flamarkt extensions.",
"keywords": [
"flarum",
"flamarkt",
"backoffice",
"admin",
"panel"
],
"type": "flarum-extension",
"license": "MIT",
"require": {
"flarum/core": "^1.2",
"ext-json": "*"
},
"authors": [
{
"name": "Flamarkt",
"homepage": "https://flamarkt.org/"
}
],
"support": {
"issues": "https://github.com/flamarkt/backoffice/issues",
"source": "https://github.com/flamarkt/backoffice"
},
"autoload": {
"psr-4": {
"Flamarkt\\Backoffice\\": "src/"
}
},
"extra": {
"flarum-extension": {
"title": "Backoffice",
"category": "feature",
"icon": {
"name": "fas fa-tachometer-alt",
"backgroundColor": "#266a13",
"color": "#fff"
}
},
"flamarkt-backoffice": {
"settingsInBackoffice": true,
"showInBackoffice": true
},
"branch-alias": {
"dev-main": "0.1.x-dev"
}
}
}
54 changes: 54 additions & 0 deletions extend.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Flamarkt\Backoffice;

use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Extend;
use Flarum\Frontend\Document;
use Illuminate\Support\Arr;

return [
// It's important for the provider to run before we call the Frontend extender with our new frontend
(new Extend\ServiceProvider())
->register(Provider\BackofficeServiceProvider::class)
->register(Provider\DatabaseServiceProvider::class),

(new Extend\Frontend('admin'))
->js(__DIR__ . '/js/dist/admin.js')
->content(function (Document $document) {
if (!$document->payload['extensions']) {
return;
}

foreach ($document->payload['extensions'] as $key => $attributes) {
if (Arr::get($attributes, 'extra.flamarkt-backoffice.hideFromAdmin')) {
unset($document->payload['extensions'][$key]);
}
}
}),

(new Extend\Frontend('backoffice'))
//->js(__DIR__ . '/js/dist/backoffice.js')
->css(__DIR__ . '/resources/less/backoffice.less')
->route('/dashboard', 'dashboard', Content\Dashboard::class)
->route('/users', 'users.index')
->route('/users/{id:[0-9]+|new}', 'users.show')
->route('/extension/{id:[a-zA-Z0-9_-]+}', 'extension'),

(new Extend\Frontend('forum'))
->js(__DIR__ . '/js/dist/forum.js'),

new Extend\Locales(__DIR__ . '/resources/locale'),

(new Extend\Middleware('forum'))
->insertBefore('flarum.forum.route_resolver', Middleware\SubForumRouter::class),

(new Extend\View())
->namespace('backoffice', __DIR__ . '/views'),

(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(ForumAttributes::class),

(new Extend\Policy())
->globalPolicy(GlobalPolicy::class),
];
1 change: 1 addition & 0 deletions js/admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/admin';
1 change: 1 addition & 0 deletions js/backoffice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/backoffice';
1 change: 1 addition & 0 deletions js/dist-typings/admin/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
19 changes: 19 additions & 0 deletions js/dist-typings/backoffice/BackofficeApplication.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Application from 'flarum/common/Application';
import ExtensionData from 'flarum/admin/utils/ExtensionData';
export default class BackofficeApplication extends Application {
extensionData: ExtensionData;
history: {
canGoBack: () => boolean;
getPrevious: () => void;
backUrl: () => unknown;
back: () => void;
};
constructor();
mount(): void;
getRequiredPermissions(permission: any): string[];
load(payload: Application["data"]): void;
get current(): import("flarum/common/states/PageState").default;
set current(value: import("flarum/common/states/PageState").default);
get previous(): import("flarum/common/states/PageState").default;
set previous(value: import("flarum/common/states/PageState").default);
}
3 changes: 3 additions & 0 deletions js/dist-typings/backoffice/app.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import BackofficeApplication from './BackofficeApplication';
declare const app: BackofficeApplication;
export default app;
31 changes: 31 additions & 0 deletions js/dist-typings/backoffice/compat.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export const backoffice: {
app: import("./BackofficeApplication").default;
'components/AbstractList': typeof AbstractList;
'components/BackofficeNav': typeof BackofficeNav;
'components/HeaderPrimary': typeof HeaderPrimary;
'components/HeaderSecondary': typeof HeaderSecondary;
'components/PermanentDeleteButton': typeof PermanentDeleteButton;
'components/SoftDeleteButton': typeof SoftDeleteButton;
'components/SubmitButton': typeof SubmitButton;
'components/UserList': typeof UserList;
'components/UserSortDropdown': typeof UserSortDropdown;
'pages/DashboardPage': typeof DashboardPage;
'pages/UserIndexPage': typeof UserIndexPage;
'pages/UserShowPage': typeof UserShowPage;
'resolvers/UserListState': typeof ExtensionPageResolver;
'states/UserListState': typeof UserListState;
};
import AbstractList from "./components/AbstractList";
import BackofficeNav from "./components/BackofficeNav";
import HeaderPrimary from "./components/HeaderPrimary";
import HeaderSecondary from "./components/HeaderSecondary";
import PermanentDeleteButton from "./components/PermanentDeleteButton";
import SoftDeleteButton from "./components/SoftDeleteButton";
import SubmitButton from "./components/SubmitButton";
import UserList from "./components/UserList";
import UserSortDropdown from "./components/UserSortDropdown";
import DashboardPage from "./pages/DashboardPage";
import UserIndexPage from "./pages/UserIndexPage";
import UserShowPage from "./pages/UserShowPage";
import ExtensionPageResolver from "./resolvers/ExtensionPageResolver";
import UserListState from "./states/UserListState";
20 changes: 20 additions & 0 deletions js/dist-typings/backoffice/components/AbstractList.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Vnode } from 'mithril';
import ItemList from 'flarum/common/utils/ItemList';
import Model from 'flarum/common/Model';
import Component, { ComponentAttrs } from 'flarum/common/Component';
import AbstractListState from '../../common/states/AbstractListState';
export interface AbstractListAttrs<T extends Model> extends ComponentAttrs {
state: AbstractListState<T>;
}
export default class AbstractList<T extends Model> extends Component<AbstractListAttrs<T>> {
items(state: AbstractListState<T>): T[];
topRow(state: AbstractListState<T>): null;
bottomRowContent(state: AbstractListState<T>): any;
bottomRow(state: AbstractListState<T>): any;
view(vnode: Vnode<AbstractListAttrs<T>>): any;
head(): ItemList<any>;
row(model: T): any;
rowAttrs(model: T): any;
columns(model: T): ItemList<any>;
actions(model: T): ItemList<any>;
}
10 changes: 10 additions & 0 deletions js/dist-typings/backoffice/components/BackofficeNav.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Vnode } from 'mithril';
import AdminNav from 'flarum/admin/components/AdminNav';
import ItemList from 'flarum/common/utils/ItemList';
export default class BackofficeNav extends AdminNav {
query: string;
oninit(vnode: Vnode): void;
items(): ItemList<unknown>;
extensions(): any[];
extensionItems(): ItemList<unknown>;
}
17 changes: 17 additions & 0 deletions js/dist-typings/backoffice/components/HeaderPrimary.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* The `HeaderPrimary` component displays primary header controls. On the
* default skin, these are shown just to the right of the forum title.
*/
export default class HeaderPrimary extends Component<any, undefined> {
constructor();
view(): JSX.Element;
config(isInitialized: any, context: any): void;
/**
* Build an item list for the controls.
*
* @return {ItemList}
*/
items(): ItemList<any>;
}
import Component from "flarum/common/Component";
import ItemList from "flarum/common/utils/ItemList";
15 changes: 15 additions & 0 deletions js/dist-typings/backoffice/components/HeaderSecondary.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* The `HeaderSecondary` component displays secondary header controls.
*/
export default class HeaderSecondary extends Component<any, undefined> {
constructor();
view(): JSX.Element;
/**
* Build an item list for the controls.
*
* @return {ItemList}
*/
items(): ItemList<any>;
}
import Component from "flarum/common/Component";
import ItemList from "flarum/common/utils/ItemList";
13 changes: 13 additions & 0 deletions js/dist-typings/backoffice/components/PermanentDeleteButton.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Component, { ComponentAttrs } from 'flarum/common/Component';
interface PermanentDeleteButtonAttrs extends ComponentAttrs {
model: {
isHidden(): boolean;
delete(): any;
};
afterdelete(): void;
}
export default class PermanentDeleteButton extends Component<PermanentDeleteButtonAttrs> {
saving: boolean;
view(): any;
}
export {};
13 changes: 13 additions & 0 deletions js/dist-typings/backoffice/components/SoftDeleteButton.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Component, { ComponentAttrs } from 'flarum/common/Component';
interface SoftDeleteButtonAttrs extends ComponentAttrs {
model: {
exists: boolean;
isHidden(): boolean;
save(attributes: any): any;
};
}
export default class SoftDeleteButton extends Component<SoftDeleteButtonAttrs> {
saving: boolean;
view(): any;
}
export {};
9 changes: 9 additions & 0 deletions js/dist-typings/backoffice/components/SubmitButton.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Vnode } from 'mithril';
import Component, { ComponentAttrs } from 'flarum/common/Component';
export interface SubmitButtonAttrs extends ComponentAttrs {
exists: boolean;
dirty: boolean;
}
export default class SubmitButton extends Component<SubmitButtonAttrs> {
view(vnode: Vnode<SubmitButtonAttrs>): Mithril.Vnode;
}
7 changes: 7 additions & 0 deletions js/dist-typings/backoffice/components/UserList.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import User from 'flarum/common/models/User';
import AbstractList from './AbstractList';
export default class UserList extends AbstractList<User> {
head(): import("flarum/common/utils/ItemList").default<any>;
columns(user: User): import("flarum/common/utils/ItemList").default<any>;
actions(user: User): import("flarum/common/utils/ItemList").default<any>;
}
9 changes: 9 additions & 0 deletions js/dist-typings/backoffice/components/UserSortDropdown.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AbstractSortDropdown, { SortDropdownAttrs, SortOptions } from '../../common/components/AbstractSortDropdown';
import UserListState from '../states/UserListState';
export interface UserSortDropdownAttrs extends SortDropdownAttrs {
state: UserListState;
}
export default class UserSortDropdown extends AbstractSortDropdown<UserSortDropdownAttrs> {
className(): string;
options(): SortOptions;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default function (): void;
5 changes: 5 additions & 0 deletions js/dist-typings/backoffice/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import app from './app';
import { common } from '../common/compat';
import { backoffice } from './compat';
export { app, // This export is used from the view file, but not by the extension imports. That other export is in the compat file
common, backoffice, };
4 changes: 4 additions & 0 deletions js/dist-typings/backoffice/pages/DashboardPage.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Page from 'flarum/common/components/Page';
export default class DashboardPage extends Page {
view(): any;
}
9 changes: 9 additions & 0 deletions js/dist-typings/backoffice/pages/UserIndexPage.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Vnode } from 'mithril';
import Page from 'flarum/common/components/Page';
import UserListState from '../states/UserListState';
export default class UserIndexPage extends Page {
list: UserListState;
oninit(vnode: Vnode): void;
initState(): UserListState;
view(): any;
}
Loading

0 comments on commit 4f3204b

Please sign in to comment.