@macellan/dux-core
v0.3.0
Published
Dux core for building and navigating rich dashboard apps
Downloads
3
Readme
Introduction
Dux is a simple boilerplate reducing tamplate for creating dashboards written in TypeScript and React. While the Dux Core doesn't have much dependencies, Dux Components package heavily relies on Mantine as a UI kit and hook library of choice. Dux is unopinonated about your state management of choice.
Installation
To get started with Dux, install the core and components package to your existing app or create a template with Codux tool (coming soon).
Using npm:
npm install @macellan/dux-core @macellan/dux-components
Using yarn:
yarn add @macellan/dux-core @macellan/dux-components
Using pnpm:
pnpm install @macellan/dux-core @macellan/dux-components
Usage
To start using the Dux Core you should create a new dux instance, best place to this would be a config file or your main.tsx
file where you initialize your react app.
This documentation will examplify the code in TypeScript but things shouldn't change much for JavaScript.
import { createDux } from '@macellan/dux-core';
const app = createDux();
Dux expects some essential options for creating an instance, like your views. Under the hood Dux uses react-router
to implement client side routing. You can pass a router object to the views
property as a router. This object can be extended with allowedRoles
propery to do authenticated routing. Dux provides 3 builtin roles to give you a headstart and handle internal mechanisms. These are;
*
Anyone can access this route.authenticated
Only users that are authenticated with given Dux primitive can access this route.unauthenticated
Only users that are unauthenticated with given Dux primitive can access this route. This is useful for creating a login or signup page that only the users that are not logged in can see.
import { createDux } from '@macellan/dux-core';
const app = createDux({
views: [
{
path: '/',
element: <div>This is the home page</div>,
// Anyone can see this page
allowedRoles: ['*'],
},
{
path: '/dashboard',
element: <div>This is the dashboard page</div>,
// Only logged in users can see this page
allowedRoles: ['authenticated'],
},
{
path: '/admin',
element: <div>This is the admin page</div>,
// You can define your arbitrary roles as well
// Only logged in users that has the admin role can see this page
allowedRoles: ['authenticated', 'admin'],
},
{
path: '/login',
element: <div>This is the login page</div>,
// Only logged out users can see this page
allowedRoles: ['unauthenticated'],
},
],
});
allowedRoles
property only works at the root level so you have to manage your routes accordingly.
Another neccessary property a Dux instance needs is the initial authentication state. Implementing the authentication is on you but we're planning a @macellan/dux-auth
package to speed up this process as well.
import { createDux } from '@macellan/dux-core';
const app = createDux({
views: [
{
path: '/',
element: <div>This is the home page</div>,
// Anyone can see this page
allowedRoles: ['*'],
},
{
path: '/dashboard',
element: <div>This is the dashboard page</div>,
// Only logged in users can see this page
allowedRoles: ['authenticated'],
},
{
path: '/admin',
element: <div>This is the admin page</div>,
// You can define your arbitrary roles as well
// Only logged in users that has the admin role can see this page
allowedRoles: ['authenticated', 'admin'],
},
{
path: '/login',
element: <div>This is the login page</div>,
// Only logged out users can see this page
allowedRoles: ['unauthenticated'],
},
],
auth: {
// For kepping track on if the user is logged in. Implement your own logic here
initialState: false,
// You should fetch your user before reaching here and provide your roles
initialRoles: [],
},
});
initialRoles
accepts a RoleObject
array, this is a simple object with a name and an identifier properties. You can provide your arbitrary roles here.
export interface RoleObject {
identifier: string;
name: string;
}
With that, you are ready to render your app. Simply create your app provider and render it with react.
// This is an async funtion that you need to wait
app.createProvider().then(DuxProvider => {
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<DuxProvider />
</React.StrictMode>
);
});
Authorization
At some point you may need an authorization manager. For instance you might want to redirect unauthroized pages or simply show an "unauthorized" view. app
instance provides a method to manage your views. You basically provide a function that would be called when Dux encounters an unauthorized view visit.
You get the view and the roles the user has in this callback function. You need to provide an object that has 2 properties;
- redirects for redirection
- replaces for displaying a custom view
You should pass null for at least one of these properties but redirection will take precedence otherwise.
app.configureAuthorizationManager((view: ViewObject, roles: RoleObject[]) => {
// Let's redirect the client if the user is 'unauthenticated'
if (roles.map(role => role.identifier).includes('unauthenticated')) {
return {
redirects: "/login",
replaces: null,
};
}
return {
redirects: null,
replaces: null,
};
})
We might want to show an "unauthorized" view for other pages.
app.configureAuthorizationManager((view: ViewObject, roles: RoleObject[]) => {
if (roles.map(role => role.identifier).includes('unauthenticated')) {
return {
redirects: "/login",
replaces: null,
};
}
// Let's first exlude views like login and signup
const authRedirectRoutes = ["/login", "/signup"]
if (authRedirectRoutes.includes(view.path as string)) {
return {
redirects: "/",
replaces: null,
};
}
// Otherwise show the unauthorized view
return {
redirects: null,
replaces: () => <div>You are not authorized to see this page</div>,
};
});
Dux provides a simple factory for this simple usage. Simply pass your primary authentication page, your non authenticated view paths, default redirect and unauthorized view to this function and you're good to go.
import { createDux, defaultAuthorizationManager } from "@macellan/dux-core"
// ...
app.configureAuthorizationManager(
defaultAuthorizationManager('/login', ['/login', '/signup'], '/', () => <div>You are not authorized to see this page</div>)
);
Authentication
Authentication is quite simple with Dux. Simply use the useAuth
hook and login and logout your user.
Dux Core does NOT handle the storage or management of the user, that is on you. Dux simply governs the auth state and the roles.
function Login() {
// use your app instance here
const { login } = app.useAuth()
const handleLogin = () => {
// Provide your users roles as a RoleObject array.
// You can pass an empty array for basic users
login([{ identifier: "admin", name: "Admin" }]);
}
return // ...
}
function UserMenu() {
// use your app instance here
const { logout } = app.useAuth()
const handleLogout = () => {
logout();
}
return // ...
}
These functions will automatically redirect the user.