feat: universal search permissions access control.

This commit is contained in:
a.bouhuolia
2021-11-27 17:22:29 +02:00
parent 56ab0a68e2
commit 3db00f6f70
14 changed files with 142 additions and 39 deletions

View File

@@ -23,6 +23,7 @@ import withDashboard from 'containers/Dashboard/withDashboard';
import QuickNewDropdown from 'containers/QuickNewDropdown/QuickNewDropdown';
import { compose } from 'utils';
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
import { useGetUniversalSearchTypeOptions } from '../../containers/UniversalSearch/utils';
function DashboardTopbarSubscriptionMessage() {
return (
@@ -142,11 +143,8 @@ function DashboardTopbar({
<Navbar class="dashboard__topbar-navbar">
<NavbarGroup>
<If condition={isSubscriptionActive}>
<Button
<DashboardQuickSearchButton
onClick={() => openGlobalSearch(true)}
className={Classes.MINIMAL}
icon={<Icon icon={'search-24'} iconSize={20} />}
text={<T id={'quick_find'} />}
/>
<QuickNewDropdown />
@@ -195,3 +193,23 @@ export default compose(
'main',
),
)(DashboardTopbar);
/**
* Dashboard quick search button.
*/
function DashboardQuickSearchButton({ ...rest }) {
const searchTypeOptions = useGetUniversalSearchTypeOptions();
// Can't continue if there is no any search type option.
if (searchTypeOptions.length <= 0) {
return null;
}
return (
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'search-24'} iconSize={20} />}
text={<T id={'quick_find'} />}
{...rest}
/>
);
}

View File

@@ -1,6 +1,10 @@
import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from 'common/resourcesTypes';
import withDrawerActions from '../Drawer/withDrawerActions';
import {
AbilitySubject,
ManualJournalAction,
} from '../../common/abilityOption';
/**
* Universal search manual journal item select action.
@@ -44,4 +48,8 @@ export const universalSearchJournalBind = () => ({
optionItemLabel: intl.get('manual_journals'),
selectItemAction: JournalUniversalSearchSelectAction,
itemSelect: manualJournalsToSearch,
permission: {
ability: ManualJournalAction.View,
subject: AbilitySubject.ManualJournal,
},
});

View File

@@ -1,7 +1,10 @@
import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from '../../common/resourcesTypes';
import withDrawerActions from '../Drawer/withDrawerActions';
import { AbilitySubject, AccountAction } from '../../common/abilityOption';
import { RESOURCES_TYPES } from '../../common/resourcesTypes';
function AccountUniversalSearchItemSelectComponent({
// #ownProps
resourceType,
@@ -42,4 +45,8 @@ export const universalSearchAccountBind = () => ({
optionItemLabel: intl.get('accounts'),
selectItemAction: AccountUniversalSearchItemSelect,
itemSelect: accountToSearch,
permission: {
ability: AccountAction.View,
subject: AbilitySubject.Account,
},
});

View File

@@ -1,4 +1,5 @@
import intl from 'react-intl-universal';
import { AbilitySubject, CustomerAction } from '../../common/abilityOption';
import { RESOURCES_TYPES } from '../../common/resourcesTypes';
import withDrawerActions from '../Drawer/withDrawerActions';
@@ -42,4 +43,8 @@ export const universalSearchCustomerBind = () => ({
optionItemLabel: intl.get('customers'),
selectItemAction: CustomerUniversalSearchSelectAction,
itemSelect: customersToSearch,
permission: {
ability: CustomerAction.View,
subject: AbilitySubject.Customer,
},
});

View File

@@ -1,7 +1,10 @@
import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from '../../common/resourcesTypes';
import withDrawerActions from '../Drawer/withDrawerActions';
import { RESOURCES_TYPES } from '../../common/resourcesTypes';
import { AbilitySubject, ItemAction } from '../../common/abilityOption';
/**
* Item univrsal search item select action.
*/
@@ -46,4 +49,8 @@ export const universalSearchItemBind = () => ({
optionItemLabel: intl.get('items'),
selectItemAction: ItemUniversalSearchSelectAction,
itemSelect: transfromItemsToSearch,
permission: {
ability: ItemAction.View,
subject: AbilitySubject.Item,
},
});

View File

@@ -7,6 +7,7 @@ import { T, Icon, Choose, If } from 'components';
import { RESOURCES_TYPES } from 'common/resourcesTypes';
import withDrawerActions from '../../Drawer/withDrawerActions';
import { AbilitySubject, BillAction } from '../../../common/abilityOption';
/**
* Universal search bill item select action.
@@ -116,4 +117,8 @@ export const universalSearchBillBind = () => ({
selectItemAction: BillUniversalSearchSelect,
itemRenderer: BillUniversalSearchItem,
itemSelect: billsToSearch,
permission: {
ability: BillAction.View,
subject: AbilitySubject.Bill,
},
});

View File

@@ -1,14 +1,14 @@
import React from 'react';
import { MenuItem } from '@blueprintjs/core';
import intl from 'react-intl-universal';
import { isEmpty } from 'lodash';
import { Icon, If } from 'components';
import { Icon } from 'components';
import { RESOURCES_TYPES } from 'common/resourcesTypes';
import withDrawerActions from '../../Drawer/withDrawerActions';
import { highlightText } from 'utils';
import { AbilitySubject, PaymentMadeAction } from '../../../common/abilityOption';
/**
* Universal search bill item select action.
@@ -82,4 +82,8 @@ export const universalSearchPaymentMadeBind = () => ({
selectItemAction: PaymentMadeUniversalSearchSelect,
itemRenderer: PaymentMadeUniversalSearchItem,
itemSelect: paymentMadeToSearch,
permission: {
ability: PaymentMadeAction.View,
subject: AbilitySubject.PaymentMade,
},
});

View File

@@ -5,6 +5,8 @@ import intl from 'react-intl-universal';
import { Choose, T, Icon } from 'components';
import { RESOURCES_TYPES } from "common/resourcesTypes";
import { AbilitySubject, SaleEstimateAction } from '../../../../common/abilityOption';
import withDrawerActions from "../../../Drawer/withDrawerActions";
/**
@@ -110,5 +112,9 @@ export const universalSearchEstimateBind = () => ({
optionItemLabel: intl.get('estimates'),
selectItemAction: EstimateUniversalSearchSelect,
itemRenderer: EstimateUniversalSearchItem,
itemSelect: transformEstimatesToSearch
itemSelect: transformEstimatesToSearch,
permission: {
ability: SaleEstimateAction.View,
subject: AbilitySubject.Estimate,
},
});

View File

@@ -3,10 +3,13 @@ import intl from 'react-intl-universal';
import { MenuItem } from '@blueprintjs/core';
import { T, Choose, Icon } from 'components';
import { highlightText } from 'utils';
import { RESOURCES_TYPES } from 'common/resourcesTypes';
import {
AbilitySubject,
SaleInvoiceAction,
} from '../../../common/abilityOption';
import withDrawerActions from '../../Drawer/withDrawerActions';
/**
@@ -118,4 +121,8 @@ export const universalSearchInvoiceBind = () => ({
selectItemAction: InvoiceUniversalSearchSelect,
itemRenderer: InvoiceUniversalSearchItem,
itemSelect: transformInvoicesToSearch,
permission: {
ability: SaleInvoiceAction.View,
subject: AbilitySubject.Invoice,
},
});

View File

@@ -2,13 +2,17 @@ import React from 'react';
import { MenuItem } from '@blueprintjs/core';
import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from "../../../common/resourcesTypes";
import withDrawerActions from "../../Drawer/withDrawerActions";
import { RESOURCES_TYPES } from '../../../common/resourcesTypes';
import withDrawerActions from '../../Drawer/withDrawerActions';
import { highlightText } from 'utils';
import { Icon } from 'components';
import {
AbilitySubject,
PaymentReceiveAction,
} from '../../../common/abilityOption';
/**
* Payment receive universal search item select action.
* Payment receive universal search item select action.
*/
function PaymentReceiveUniversalSearchSelectComponent({
// #ownProps
@@ -19,7 +23,9 @@ function PaymentReceiveUniversalSearchSelectComponent({
openDrawer,
}) {
if (resourceType === RESOURCES_TYPES.PAYMENT_RECEIVE) {
openDrawer('payment-receive-detail-drawer', { paymentReceiveId: resourceId });
openDrawer('payment-receive-detail-drawer', {
paymentReceiveId: resourceId,
});
}
return null;
}
@@ -59,7 +65,7 @@ export function PaymentReceiveUniversalSearchItem(
/**
* Transformes payment receives to search.
*/
const paymentReceivesToSearch = (payment) => ({
const paymentReceivesToSearch = (payment) => ({
id: payment.id,
text: payment.customer.display_name,
subText: payment.formatted_payment_date,
@@ -70,10 +76,14 @@ export function PaymentReceiveUniversalSearchItem(
/**
* Binds universal search payment receive configure.
*/
export const universalSearchPaymentReceiveBind = () => ({
export const universalSearchPaymentReceiveBind = () => ({
resourceType: RESOURCES_TYPES.PAYMENT_RECEIVE,
optionItemLabel: intl.get('payment_receives'),
selectItemAction: PaymentReceiveUniversalSearchSelect,
itemRenderer: PaymentReceiveUniversalSearchItem,
itemSelect: paymentReceivesToSearch,
permission: {
ability: PaymentReceiveAction.View,
subject: AbilitySubject.PaymentReceive,
},
});

View File

@@ -1,16 +1,18 @@
import React from 'react';
import intl from 'react-intl-universal';
import { MenuItem } from '@blueprintjs/core';
import { Icon, Choose, T } from 'components';
import { RESOURCES_TYPES } from "../../../common/resourcesTypes";
import withDrawerActions from "../../Drawer/withDrawerActions";
import { RESOURCES_TYPES } from '../../../common/resourcesTypes';
import withDrawerActions from '../../Drawer/withDrawerActions';
import {
AbilitySubject,
SaleReceiptAction,
} from '../../../common/abilityOption';
/**
* Receipt universal search item select action.
* Receipt universal search item select action.
*/
function ReceiptUniversalSearchSelectComponent({
// #ownProps
@@ -39,11 +41,15 @@ function ReceiptStatus({ receipt }) {
return (
<Choose>
<Choose.When condition={receipt.is_closed}>
<span class="closed"><T id={'closed'} /></span>
<span class="closed">
<T id={'closed'} />
</span>
</Choose.When>
<Choose.Otherwise>
<span class="draft"><T id={'draft'} /></span>
<span class="draft">
<T id={'draft'} />
</span>
</Choose.Otherwise>
</Choose>
);
@@ -100,4 +106,8 @@ export const universalSearchReceiptBind = () => ({
selectItemAction: ReceiptUniversalSearchSelect,
itemRenderer: ReceiptUniversalSearchItem,
itemSelect: transformReceiptsToSearch,
permission: {
ability: SaleReceiptAction.View,
subject: AbilitySubject.Receipt,
},
});

View File

@@ -14,7 +14,7 @@ import DashboardUniversalSearchItemActions from './DashboardUniversalSearchItemA
import { DashboardUniversalSearchItem } from './components';
import DashboardUniversalSearchHotkeys from './DashboardUniversalSearchHotkeys';
import { getUniversalSearchTypeOptions } from './utils';
import { useGetUniversalSearchTypeOptions } from './utils';
/**
* Dashboard universal search.
@@ -28,6 +28,8 @@ function DashboardUniversalSearch({
closeGlobalSearch,
defaultUniversalResourceType,
}) {
const searchTypeOptions = useGetUniversalSearchTypeOptions();
// Search keyword.
const [searchKeyword, setSearchKeyword] = React.useState('');
@@ -97,10 +99,9 @@ function DashboardUniversalSearch({
setSearchKeyword('');
};
const searchTypeOptions = React.useMemo(
() => getUniversalSearchTypeOptions(),
[],
);
if (searchTypeOptions.length === 0) {
return null;
}
return (
<div class="dashboard__universal-search">

View File

@@ -1,5 +1,9 @@
import { get } from 'lodash';
import * as R from 'ramda';
import React from 'react';
import { universalSearchBinds } from './DashboardUniversalSearchBinds';
import { useAbilitiesFilter } from '../../hooks/utils';
/**
*
@@ -23,22 +27,28 @@ export const getUniversalSearchBind = (resourceType, key) => {
};
/**
*
* @returns
* Retrieve universal search type options.
*/
export const getUniversalSearchTypeOptions = () => {
return getUniversalSearchBinds().map((bind) => ({
key: bind.resourceType,
label: bind.optionItemLabel,
}))
}
export const useGetUniversalSearchTypeOptions = () => {
const abilityFilter = useAbilitiesFilter();
const momerizedBinds = React.useMemo(() => {
const filteredBinds = R.compose(abilityFilter, getUniversalSearchBinds)();
return filteredBinds.map((bind) => ({
key: bind.resourceType,
label: bind.optionItemLabel,
}));
}, [abilityFilter]);
return momerizedBinds;
};
/**
*
* @returns
* Retrieve universal search types actions.
*/
export const getUniversalSearchItemsActions = () => {
return getUniversalSearchBinds()
.filter((bind) => bind.selectItemAction)
.map((bind) => bind.selectItemAction);
}
};

View File

@@ -1,6 +1,7 @@
import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from '../../common/resourcesTypes';
import { AbilitySubject, VendorAction } from '../../common/abilityOption';
import withDrawerActions from '../Drawer/withDrawerActions';
/**
@@ -43,4 +44,8 @@ export const universalSearchVendorBind = () => ({
optionItemLabel: intl.get('vendors'),
selectItemAction: VendorUniversalSearchSelectAction,
itemSelect: vendorToSearch,
permission: {
ability: VendorAction.View,
subject: AbilitySubject.Vendor,
},
});