Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,12 @@ Most times you need to refresh the badge from some backend API or hook. To do th
resourceId: 'posts',
//diff-add
itemId: 'postsMenuItem',
badge: async (adminUser: AdminUser) => {
return 10
//diff-add
badge: async (adminUser: AdminUser, adminForth: IAdminForth) => {
//diff-add
const newCount = await adminforth.resource('posts').count(Filters.EQ('verified', false));
//diff-add
return newCount;
},
badgeTooltip: 'Unverified posts', // explain user what this badge means
...
Expand All @@ -226,15 +230,13 @@ Most times you need to refresh the badge from some backend API or hook. To do th
table: 'posts',
hooks: {
edit: {
//diff-add
//diff-add
afterSave: async ({ record, adminUser, resource, adminforth }) => {
//diff-add
const newCount = await adminforth.resource('posts').count(Filters.EQ('verified', false));
//diff-add
adminforth.websocket.publish(`/opentopic/update-menu-badge/postsMenuItem`, { badge: newCount });
//diff-add
//diff-add
adminforth.refreshMenuBadge('postsMenuItem', adminUser);
//diff-add
return { ok: true }
//diff-add
//diff-add
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions adminforth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ class AdminForth implements IAdminForth {

websocket: IWebSocketBroker;

async refreshMenuBadge(menuItemId: string, adminUser: AdminUser) {
const menuItem = this.config.menu.find((item) => item.itemId === menuItemId);
if (!menuItem) {
afLogger.error(`Cannot refresh badge for menu item with id "${menuItemId}" because it was not found in config.menu`);
return;
}
if (!menuItem.badge) {
afLogger.error(`Cannot refresh badge for menu item with id "${menuItemId}" because it does not have badge function in config.menu`);
return;
}
const badgeValue = typeof menuItem.badge === 'function' ? await menuItem.badge(adminUser, this) : menuItem.badge;
this.websocket.publish(`/opentopic/update-menu-badge/${menuItemId}`, { badge: badgeValue });
}

operationalResources: {
[resourceId: string]: IOperationalResource,
}
Expand Down
4 changes: 3 additions & 1 deletion adminforth/modules/restApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,11 +504,13 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {

const badgeFunctions = [];

const adminforth = this.adminforth;

function processMenuItem(menuItem) {
if (menuItem.badge) {
if (typeof menuItem.badge === 'function') {
badgeFunctions.push(async () => {
badges[menuItem.itemId] = await menuItem.badge(adminUser);
badges[menuItem.itemId] = await menuItem.badge(adminUser, adminforth);
});
} else {
badges[menuItem.itemId] = menuItem.badge;
Expand Down
2 changes: 2 additions & 0 deletions adminforth/types/Back.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ export interface IAdminForth {
* ```
*/
getPluginById<T>(id: string): T;

refreshMenuBadge(menuItemId: string, adminUser: AdminUser): Promise<void>;
}


Expand Down
2 changes: 1 addition & 1 deletion adminforth/types/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,7 @@ export interface AdminForthConfigMenuItem {
* Optional callback which will be called before rendering the menu for each item.
* Result of callback if not null will be used as a small badge near the menu item.
*/
badge?: string | ((user: AdminUser) => Promise<string>),
badge?: string | number | ((user: AdminUser, adminForth: IAdminForth) => Promise<string | number> | string | number),

/**
* Tooltip shown on hover for badge
Expand Down
8 changes: 5 additions & 3 deletions dev-demo/api.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Express } from "express";
import { IAdminForth } from "adminforth";
import { IAdminForth, IAdminUserExpressRequest } from "adminforth";

export function initApi(app: Express, admin: IAdminForth) {
app.get(`${admin.config.baseUrl}/api/hello/`,
(req, res) => {
admin.express.authorize(
async (req:IAdminUserExpressRequest, res: any) => {
admin.refreshMenuBadge('menuTimestamp', req.adminUser);
res.json({ message: "Hello from AdminForth API!" });
}
);
));
}
21 changes: 21 additions & 0 deletions dev-demo/custom/AfComponents.vue
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,18 @@
:expandDepth="2"
/>

<Button @click="createJob">
Create Job
</Button>

<Button @click="callHelloWorldApi">
Call API
</Button>

<Button @click="callHelloWorldApi">
Refresh badge
</Button>

</div>


Expand Down Expand Up @@ -522,4 +534,13 @@ watch(numberInput, (newVal) => {
watch(textInput, (newVal) => {
console.log('Text input changed:', newVal, typeof newVal);
});

async function callHelloWorldApi() {
try {
const response = await callApi({ path: '/api/hello/', method: 'GET' });
console.log('API response:', response);
} catch (error) {
console.error('API error:', error);
}
}
</script>
8 changes: 7 additions & 1 deletion dev-demo/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express';
import AdminForth, { Filters } from '../adminforth/index.js';
import AdminForth, { AdminUser, Filters, IAdminForth } from '../adminforth/index.js';
import usersResource from "./resources/adminuser.js";
import { fileURLToPath } from 'url';
import path from 'path';
Expand Down Expand Up @@ -143,6 +143,12 @@ export const admin = new AdminForth({
icon: 'flowbite:chart-pie-solid',
component: '@@/AfComponents.vue',
path: '/af-components',
itemId: 'menuTimestamp',
badge: async (adminUser: AdminUser, adminForth: IAdminForth) => {
const now = new Date();
return now.getSeconds();
},
badgeTooltip: 'Seconds in current minute',
},
{
type: 'divider'
Expand Down