From a21d70a59d07804c400680eda3075683632fa053 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Fri, 26 Nov 2021 19:07:18 +0200 Subject: [PATCH 1/2] feat: sidebar permission access control. --- src/common/abilityOption.js | 19 + .../Dashboard/DashboardAbilityProvider.js | 2 +- src/components/Dashboard/DashboardBoot.js | 1 - src/components/Sidebar/Sidebar.js | 5 +- src/components/Sidebar/SidebarMenu.js | 6 +- src/components/Sidebar/utils.js | 48 ++ src/config/sidebarMenu.js | 471 +++++++++++++++++- 7 files changed, 538 insertions(+), 14 deletions(-) create mode 100644 src/components/Sidebar/utils.js diff --git a/src/common/abilityOption.js b/src/common/abilityOption.js index 5661b6167..4d2bbac39 100644 --- a/src/common/abilityOption.js +++ b/src/common/abilityOption.js @@ -14,6 +14,9 @@ export const AbilitySubject = { Expense: 'Expense', Cashflow: 'Cashflow', Report: 'Report', + Preferences: 'Preferences', + ExchangeRate: 'ExchangeRate', + SubscriptionBilling: 'SubscriptionBilling' }; export const Item_Abilities = { @@ -99,6 +102,7 @@ export const Manual_Journal_Abilities = { Create: 'create', Edit: 'edit', Delete: 'delete', + TransactionLocking: 'TransactionLocking' }; export const Expense_Abilities = { @@ -134,3 +138,18 @@ export const Report_Abilities = { READ_INVENTORY_ITEM_DETAILS: 'read-inventory-item-details', READ_CASHFLOW_ACCOUNT_TRANSACTION: 'read-cashflow-account-transactions', }; + +export const PreferencesAbility = { + Mutate: 'Mutate' +} + +export const ExchangeRateAbility ={ + View: 'view', + Create: 'create', + Delete: 'delete', +} + +export const SubscriptionBillingAbility = { + View: 'view', + Payment: 'payment' +} \ No newline at end of file diff --git a/src/components/Dashboard/DashboardAbilityProvider.js b/src/components/Dashboard/DashboardAbilityProvider.js index b34166489..37de0ced2 100644 --- a/src/components/Dashboard/DashboardAbilityProvider.js +++ b/src/components/Dashboard/DashboardAbilityProvider.js @@ -15,7 +15,7 @@ export function DashboardAbilityProvider({ children }) { } = useDashboardMeta(); // Ability instance. - const ability = new Ability([]); + const ability = new Ability(abilities); return ( diff --git a/src/components/Dashboard/DashboardBoot.js b/src/components/Dashboard/DashboardBoot.js index d2b565c56..738c45115 100644 --- a/src/components/Dashboard/DashboardBoot.js +++ b/src/components/Dashboard/DashboardBoot.js @@ -7,7 +7,6 @@ import { } from '../../hooks/query'; import { useSplashLoading } from '../../hooks/state'; import { useWatch, useWatchImmediate, useWhen } from '../../hooks'; - import { setCookie, getCookie } from '../../utils'; /** diff --git a/src/components/Sidebar/Sidebar.js b/src/components/Sidebar/Sidebar.js index 8d6688f7c..676425b18 100644 --- a/src/components/Sidebar/Sidebar.js +++ b/src/components/Sidebar/Sidebar.js @@ -2,16 +2,19 @@ import React from 'react'; import SidebarContainer from 'components/Sidebar/SidebarContainer'; import SidebarHead from 'components/Sidebar/SidebarHead'; import SidebarMenu from 'components/Sidebar/SidebarMenu'; +import { useGetSidebarMenu } from './utils'; import 'style/containers/Dashboard/Sidebar.scss'; export default function Sidebar({ dashboardContentRef }) { + const menu = useGetSidebarMenu(); + return (
- +
diff --git a/src/components/Sidebar/SidebarMenu.js b/src/components/Sidebar/SidebarMenu.js index 56c667806..5a8d2bd82 100644 --- a/src/components/Sidebar/SidebarMenu.js +++ b/src/components/Sidebar/SidebarMenu.js @@ -1,7 +1,7 @@ import React from 'react'; import { Menu, MenuDivider } from '@blueprintjs/core'; import { useHistory, useLocation } from 'react-router-dom'; -import sidebarMenuList from 'config/sidebarMenu'; + import { Choose } from 'components'; import Icon from 'components/Icon'; import MenuItem from 'components/MenuItem'; @@ -24,7 +24,7 @@ function SidebarMenuItemSpace({ space }) { return
; } -function SidebarMenu({ isSubscriptionActive }) { +function SidebarMenu({ menu, isSubscriptionActive }) { const history = useHistory(); const location = useLocation(); @@ -93,7 +93,7 @@ function SidebarMenu({ isSubscriptionActive }) { }); }; - const filterItems = sidebarMenuList.filter( + const filterItems = menu.filter( (item) => isSubscriptionActive || item.enableBilling, ); const items = menuItemsMapper(filterItems); diff --git a/src/components/Sidebar/utils.js b/src/components/Sidebar/utils.js new file mode 100644 index 000000000..fcf056fac --- /dev/null +++ b/src/components/Sidebar/utils.js @@ -0,0 +1,48 @@ +import sidebarMenuList from 'config/sidebarMenu'; +import { isArray, isEmpty } from 'lodash'; +import { useAbilityContext } from 'hooks/utils'; + +export function useGetSidebarMenu() { + const ability = useAbilityContext(); + + return sidebarMenuList + .map((item) => { + const children = isArray(item.children) + ? item.children.filter((childItem) => { + return isArray(childItem.permission) + ? childItem.permission.some((perm) => + ability.can(perm.ability, perm.subject), + ) + : childItem?.permission?.ability && childItem?.permission?.subject + ? ability.can( + childItem.permission.ability, + childItem.permission.subject, + ) + : true; + }) + : []; + + return { + ...item, + ...(isArray(item.children) + ? { + children, + } + : {}), + }; + }) + .filter((item) => { + return isArray(item.permission) + ? item.permission.some((per) => + ability.can(per.ability, per.subject), + ) + : item?.permission?.ability && item?.permission?.subject + ? ability.can(item.permission.ability, item.permission.subject) + : true; + }) + .filter((item) => + isEmpty(item.children) && !item.href && !item.label && !item.divider + ? false + : true, + ); +} diff --git a/src/config/sidebarMenu.js b/src/config/sidebarMenu.js index bb02d9100..0c5d34abb 100644 --- a/src/config/sidebarMenu.js +++ b/src/config/sidebarMenu.js @@ -1,5 +1,26 @@ import React from 'react'; import { FormattedMessage as T } from 'components'; +import { + Report_Abilities, + AbilitySubject, + Item_Abilities, + Inventory_Adjustment_Abilities, + Estimate_Abilities, + Invoice_Abilities, + Receipt_Abilities, + Payment_Receive_Abilities, + Bill_Abilities, + Payment_Made_Abilities, + Customer_Abilities, + Vendor_Abilities, + Account_Abilities, + Manual_Journal_Abilities, + Expense_Abilities, + Cashflow_Abilities, + PreferencesAbility, + ExchangeRateAbility, + SubscriptionBillingAbility, +} from '../common/abilityOption'; export default [ { @@ -11,6 +32,32 @@ export default [ { text: , label: true, + permission: [ + { + subject: AbilitySubject.Item, + ability: Item_Abilities.View, + }, + { + subject: AbilitySubject.Inventory_Adjustment, + ability: Inventory_Adjustment_Abilities.View, + }, + { + subject: AbilitySubject.Estimate, + ability: Estimate_Abilities.View, + }, + { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.View, + }, + { + subject: AbilitySubject.Receipt, + ability: Receipt_Abilities.View, + }, + { + subject: AbilitySubject.PaymentReceive, + ability: Payment_Receive_Abilities.View, + } + ], }, { text: , @@ -18,37 +65,70 @@ export default [ { text: , href: '/items', + permission: { + subject: AbilitySubject.Item, + ability: Item_Abilities.View, + }, }, { text: , href: '/inventory-adjustments', + permission: { + subject: AbilitySubject.Inventory_Adjustment, + ability: Inventory_Adjustment_Abilities.View, + }, }, { text: , href: '/items/categories', + permission: { + subject: AbilitySubject.Item, + ability: Item_Abilities.View, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Item, + ability: Item_Abilities.Create, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Item, + ability: Item_Abilities.Create, + }, + ], }, { text: , href: '/items/new', + permission: { + subject: AbilitySubject.Item, + ability: Item_Abilities.Create, + }, }, { text: , href: '/items/new', + permission: { + subject: AbilitySubject.Item, + ability: Item_Abilities.Create, + }, }, { text: , href: '/items/categories/new', + permission: { + subject: AbilitySubject.Item, + ability: Item_Abilities.Create, + }, }, - // { - // text: , - // }, ], }, { @@ -57,43 +137,109 @@ export default [ { text: , href: '/estimates', - newTabHref: '/estimates/new', + permission: { + subject: AbilitySubject.Estimate, + ability: Estimate_Abilities.View, + }, }, { text: , href: '/invoices', - newTabHref: '/invoices/new', + permission: { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.View, + }, }, { text: , href: '/receipts', + permission: { + subject: AbilitySubject.Receipt, + ability: Receipt_Abilities.View, + }, }, { text: , href: '/payment-receives', + permission: { + subject: AbilitySubject.PaymentReceive, + ability: Payment_Receive_Abilities.View, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Estimate, + ability: Estimate_Abilities.Create, + }, + { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.Create, + }, + { + subject: AbilitySubject.Receipt, + ability: Receipt_Abilities.Create, + }, + { + subject: AbilitySubject.PaymentReceive, + ability: Payment_Receive_Abilities.Create, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Estimate, + ability: Estimate_Abilities.Create, + }, + { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.Create, + }, + { + subject: AbilitySubject.Receipt, + ability: Receipt_Abilities.Create, + }, + { + subject: AbilitySubject.PaymentReceive, + ability: Payment_Receive_Abilities.Create, + }, + ], }, { text: , href: '/estimates/new', + permission: { + subject: AbilitySubject.Estimate, + ability: Estimate_Abilities.Create, + }, }, { text: , href: '/invoices/new', + permission: { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.Create, + }, }, { text: , href: '/receipts/new', + permission: { + subject: AbilitySubject.Receipt, + ability: Receipt_Abilities.Create, + }, }, { text: , href: '/payment-receives/new', + permission: { + subject: AbilitySubject.PaymentReceive, + ability: Payment_Receive_Abilities.Create, + }, }, ], }, @@ -103,27 +249,62 @@ export default [ { text: , href: '/bills', - newTabHref: '/bills/new', + permission: { + subject: AbilitySubject.Bill, + ability: Bill_Abilities.View, + }, }, { text: , href: '/payment-mades', newTabHref: '/payment-mades/new', + permission: { + subject: AbilitySubject.PaymentMade, + ability: Payment_Made_Abilities.View, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Bill, + ability: Bill_Abilities.Create, + }, + { + subject: AbilitySubject.PaymentMade, + ability: Payment_Made_Abilities.Create, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Bill, + ability: Bill_Abilities.Create, + }, + { + subject: AbilitySubject.PaymentMade, + ability: Payment_Made_Abilities.Create, + }, + ], }, { text: , href: '/bills/new', + permission: { + subject: AbilitySubject.Bill, + ability: Bill_Abilities.Create, + }, }, { text: , href: '/payment-mades/new', + permission: { + subject: AbilitySubject.PaymentMade, + ability: Payment_Made_Abilities.Create, + }, }, ], }, @@ -133,33 +314,77 @@ export default [ { text: , href: '/customers', - newTabHref: '/customers/new', + permission: { + subject: AbilitySubject.Customer, + ability: Customer_Abilities.View, + }, }, { text: , href: '/vendors', - newTabHref: '/vendors/new', + permission: { + subject: AbilitySubject.Vendor, + ability: Vendor_Abilities.Create, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Customer, + ability: Customer_Abilities.View, + }, + { + subject: AbilitySubject.Vendor, + ability: Vendor_Abilities.View, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Customer, + ability: Customer_Abilities.View, + }, + { + subject: AbilitySubject.Vendor, + ability: Vendor_Abilities.View, + }, + ], }, { text: , href: '/customers/new', + permission: { + subject: AbilitySubject.Customer, + ability: Customer_Abilities.View, + }, }, { text: , href: '/vendors/new', + permission: { + subject: AbilitySubject.Vendor, + ability: Vendor_Abilities.View, + }, }, ], }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Account, + ability: Account_Abilities.View, + }, + { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.View, + }, + ], }, { text: , @@ -167,29 +392,57 @@ export default [ { text: , href: '/accounts', + permission: { + subject: AbilitySubject.Account, + ability: Account_Abilities.View, + }, }, { text: , href: '/manual-journals', + permission: { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.View, + }, }, { text: , href: '/transactions-locking', + permission: { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.TransactionLocking, + }, }, { text: , href: '/exchange-rates', + permission: { + subject: AbilitySubject.ExchangeRate, + ability: ExchangeRateAbility.View, + }, }, { text: , label: true, + permission: { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.Create, + }, }, { divider: true, + permission: { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.Create, + }, }, { text: , href: '/make-journal-entry', + permission: { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.Create, + }, }, ], }, @@ -199,29 +452,61 @@ export default [ { text: , href: '/cashflow-accounts', + permission: { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.View, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.Create, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.Create, + }, + ], }, { text: , href: '/cashflow-accounts', + permission: { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.Create, + }, }, { text: , href: '/cashflow-accounts', + permission: { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.Create, + }, }, { text: , href: '/cashflow-accounts', + permission: { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.Create, + }, }, { text: , href: '/cashflow-accounts', + permission: { + subject: AbilitySubject.Cashflow, + ability: Cashflow_Abilities.Create, + }, }, ], }, @@ -231,17 +516,33 @@ export default [ { text: , href: '/expenses', + permission: { + subject: AbilitySubject.Expense, + ability: Expense_Abilities.View, + }, }, { text: , label: true, + permission: { + subject: AbilitySubject.Expense, + ability: Expense_Abilities.Create, + }, }, { divider: true, + permission: { + subject: AbilitySubject.Expense, + ability: Expense_Abilities.Create, + }, }, { text: , href: '/expenses/new', + permission: { + subject: AbilitySubject.Expense, + ability: Expense_Abilities.Create, + }, }, ], }, @@ -251,80 +552,216 @@ export default [ { text: , href: '/financial-reports/balance-sheet', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_BALANCE_SHEET, + }, }, { text: , href: '/financial-reports/trial-balance-sheet', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_TRIAL_BALANCE_SHEET, + }, }, { text: , href: '/financial-reports/journal-sheet', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_JOURNAL, + }, }, { text: , href: '/financial-reports/general-ledger', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_GENERAL_LEDGET, + }, }, { text: , href: '/financial-reports/profit-loss-sheet', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_PROFIT_LOSS, + }, }, { text: , href: '/financial-reports/cash-flow', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CASHFLOW_ACCOUNT_TRANSACTION, + }, }, { text: , href: '/financial-reports/receivable-aging-summary', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_AR_AGING_SUMMARY, + }, }, { text: , href: '/financial-reports/payable-aging-summary', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_AP_AGING_SUMMARY, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_PURCHASES_BY_ITEMS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_SALES_BY_ITEMS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CUSTOMERS_TRANSACTIONS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_VENDORS_TRANSACTIONS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CUSTOMERS_SUMMARY_BALANCE, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_VENDORS_SUMMARY_BALANCE, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_PURCHASES_BY_ITEMS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_SALES_BY_ITEMS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CUSTOMERS_TRANSACTIONS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_VENDORS_TRANSACTIONS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CUSTOMERS_SUMMARY_BALANCE, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_VENDORS_SUMMARY_BALANCE, + }, + ], }, { text: , href: '/financial-reports/purchases-by-items', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_PURCHASES_BY_ITEMS, + }, }, { text: , href: '/financial-reports/sales-by-items', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_SALES_BY_ITEMS, + }, }, { text: , href: '/financial-reports/transactions-by-customers', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CUSTOMERS_TRANSACTIONS, + }, }, { text: , href: '/financial-reports/transactions-by-vendors', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_VENDORS_TRANSACTIONS, + }, }, { text: , href: '/financial-reports/customers-balance-summary', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_CUSTOMERS_SUMMARY_BALANCE, + }, }, { text: , href: '/financial-reports/vendors-balance-summary', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_VENDORS_SUMMARY_BALANCE, + }, }, { text: , label: true, + permission: [ + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_INVENTORY_ITEM_DETAILS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_INVENTORY_VALUATION_SUMMARY, + }, + ], }, { divider: true, + permission: [ + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_INVENTORY_ITEM_DETAILS, + }, + { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_INVENTORY_VALUATION_SUMMARY, + }, + ], }, { text: , href: '/financial-reports/inventory-item-details', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_INVENTORY_ITEM_DETAILS, + }, }, { text: , href: '/financial-reports/inventory-valuation', + permission: { + subject: AbilitySubject.Report, + ability: Report_Abilities.READ_INVENTORY_VALUATION_SUMMARY, + }, }, ], }, @@ -332,14 +769,32 @@ export default [ text: , enableBilling: true, label: true, + permission: [ + { + subject: AbilitySubject.Preferences, + ability: PreferencesAbility.Mutate, + }, + { + subject: AbilitySubject.SubscriptionBilling, + ability: SubscriptionBillingAbility.View, + }, + ], }, { text: , href: '/preferences', + permission: { + subject: AbilitySubject.Preferences, + ability: PreferencesAbility.Mutate, + }, }, { text: , href: '/billing', enableBilling: true, + permission: { + subject: AbilitySubject.SubscriptionBilling, + ability: SubscriptionBillingAbility.View, + }, }, ]; From ccad55dd4ae91294f1147835162c1674203e4ba4 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Fri, 26 Nov 2021 19:37:36 +0200 Subject: [PATCH 2/2] feat: dashboard quick new access control. --- src/common/quickNewOptions.js | 73 +++++++++++++++++-- .../QuickNewDropdown/QuickNewDropdown.js | 11 ++- src/hooks/utils/useAbilityContext.js | 20 ++++- 3 files changed, 94 insertions(+), 10 deletions(-) diff --git a/src/common/quickNewOptions.js b/src/common/quickNewOptions.js index 74b9fece8..09572523e 100644 --- a/src/common/quickNewOptions.js +++ b/src/common/quickNewOptions.js @@ -1,10 +1,71 @@ import intl from 'react-intl-universal'; +import { + AbilitySubject, + Invoice_Abilities, + Customer_Abilities, + Vendor_Abilities, + Manual_Journal_Abilities, + Expense_Abilities, +} from '../common/abilityOption'; +import { useAbilitiesFilter } from '../hooks'; export const getQuickNewActions = () => [ - { path: 'invoices/new', name: intl.get('sale_invoice') }, - { path: 'bills/new', name: intl.get('purchase_invoice') }, - { path: 'make-journal-entry', name: intl.get('manual_journal') }, - { path: 'expenses/new', name: intl.get('expense') }, - { path: 'customers/new', name: intl.get('customer') }, - { path: 'vendors/new', name: intl.get('vendor') }, + { + path: 'invoices/new', + name: intl.get('sale_invoice'), + permission: { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.Create, + }, + }, + { + path: 'bills/new', + name: intl.get('purchase_invoice'), + permission: { + subject: AbilitySubject.Invoice, + ability: Invoice_Abilities.Create, + }, + }, + { + path: 'make-journal-entry', + name: intl.get('manual_journal'), + permission: { + subject: AbilitySubject.ManualJournal, + ability: Manual_Journal_Abilities.Create, + }, + }, + { + path: 'expenses/new', + name: intl.get('expense'), + permission: { + subject: AbilitySubject.Expense, + ability: Expense_Abilities.Create, + }, + }, + { + path: 'customers/new', + name: intl.get('customer'), + permission: { + subject: AbilitySubject.Customer, + ability: Customer_Abilities.Create, + }, + }, + { + path: 'vendors/new', + name: intl.get('vendor'), + permission: { + subject: AbilitySubject.Vendor, + ability: Vendor_Abilities.Vendor, + }, + }, ]; + +/** + * Retrieve the dashboard quick new menu items. + */ +export const useGetQuickNewMenu = () => { + const quickNewMenu = getQuickNewActions(); + const abilitiesFilter = useAbilitiesFilter(); + + return abilitiesFilter(quickNewMenu); +}; diff --git a/src/containers/QuickNewDropdown/QuickNewDropdown.js b/src/containers/QuickNewDropdown/QuickNewDropdown.js index a3489d21d..a6242e2af 100644 --- a/src/containers/QuickNewDropdown/QuickNewDropdown.js +++ b/src/containers/QuickNewDropdown/QuickNewDropdown.js @@ -4,16 +4,21 @@ import { FormattedMessage as T } from 'components'; import { useHistory } from 'react-router-dom'; import { Icon } from 'components'; import { Position } from '@blueprintjs/core'; -import { getQuickNewActions } from 'common/quickNewOptions'; import { Select } from '@blueprintjs/select'; +import { useGetQuickNewMenu } from 'common/quickNewOptions'; + /** * Quick New Dropdown. */ export default function QuickNewDropdown() { const history = useHistory(); - const quickNewOptions = getQuickNewActions(); + const quickNewOptions = useGetQuickNewMenu(); + // Can't continue if there is no any quick new menu items to display. + if (quickNewOptions.length === 0) { + return null; + } // Handle click quick new button. const handleClickQuickNew = ({ path }) => { history.push(`/${path}`); @@ -40,4 +45,4 @@ export default function QuickNewDropdown() { /> ); -} \ No newline at end of file +} diff --git a/src/hooks/utils/useAbilityContext.js b/src/hooks/utils/useAbilityContext.js index 4aca97f3d..9d530e0ec 100644 --- a/src/hooks/utils/useAbilityContext.js +++ b/src/hooks/utils/useAbilityContext.js @@ -1,4 +1,22 @@ +import React from 'react'; import { useAbility } from '@casl/react'; import { AbilityContext } from '../../components'; -export const useAbilityContext = () => useAbility(AbilityContext); \ No newline at end of file +export const useAbilityContext = () => useAbility(AbilityContext); + +/** + * + */ +export const useAbilitiesFilter = () => { + const ability = useAbilityContext(); + + return React.useCallback( + (items) => { + return items.filter((item) => + ability.can(item.permission.ability, item.permission.subject), + ); + }, + [ability], + ); +}; + \ No newline at end of file