feat: item & inventory.

This commit is contained in:
elforjani13
2021-11-23 16:51:40 +02:00
parent afee2e90e0
commit e5d02043ad
11 changed files with 177 additions and 106 deletions

View File

@@ -0,0 +1,17 @@
export const AbilitySubject = {
Item: 'Item',
InventoryAdjustment: 'InventoryAdjustment',
};
export const ItemAbility = {
View: 'view',
Create: 'create',
Edit: 'edit',
Delete: 'delete',
};
export const InventoryAdjustment = {
View: 'view',
Create: 'create',
Delete: 'delete',
};

View File

@@ -1,10 +0,0 @@
import { AbilityBuilder, defineAbility } from '@casl/ability';
import { createContextualCan } from '@casl/react';
import { createContext } from 'react';
export const AbilityContext = createContext();
export const Can = createContextualCan(AbilityContext.Consumer);
export const ability = defineAbility((can, cannot) => {
cannot('Item', 'create');
});

View File

@@ -1,4 +1,29 @@
import { createCanBoundTo } from '@casl/react'; import React from 'react';
import ability from '../components/Config/ability'; import { Ability } from '@casl/ability';
import { createContextualCan } from '@casl/react';
export default createCanBoundTo(ability); import {
ItemAbility,
AbilitySubject,
InventoryAdjustment,
} from '../common/abilityOption';
export const AbilityContext = React.createContext();
export const Can = createContextualCan(AbilityContext.Consumer);
const AbilityContextProvider = (props) => {
const ability = new Ability([
{
subject: [AbilitySubject.Item],
action: [ItemAbility.Create, ItemAbility.Edit],
},
]);
return (
<AbilityContext.Provider value={ability}>
{props.children}
</AbilityContext.Provider>
);
};
export default AbilityContextProvider;

View File

@@ -1,10 +0,0 @@
import { AbilityBuilder } from '@casl/ability';
// import { AbilitySubject, ItemAbility } from '../../common/abilityOption';
export function defineAbilitiesFor(role) {
const { rules, can } = new AbilityBuilder();
can('create', 'Item');
return new Ability(rules);
}

View File

@@ -1,8 +1,9 @@
import React from 'react'; import React from 'react';
import AbilityContextProvider from '../../components/Can';
/** /**
* Dashboard provider. * Dashboard provider.
*/ */
export default function DashboardProvider({ children }) { export default function DashboardProvider({ children }) {
return children; return <AbilityContextProvider>{children}</AbilityContextProvider>;
} }

View File

@@ -59,6 +59,7 @@ import AvaterCell from './AvaterCell';
import { ItemsMultiSelect } from './Items'; import { ItemsMultiSelect } from './Items';
import MoreMenuItems from './MoreMenutItems'; import MoreMenuItems from './MoreMenutItems';
import { Can } from './Can';
export * from './Dialog'; export * from './Dialog';
export * from './Menu'; export * from './Menu';
@@ -156,4 +157,5 @@ export {
Card, Card,
AvaterCell, AvaterCell,
MoreMenuItems, MoreMenuItems,
Can,
}; };

View File

@@ -7,7 +7,11 @@ import { useInventoryAdjustmentDrawerContext } from './InventoryAdjustmentDrawer
import withAlertsActions from 'containers/Alert/withAlertActions'; import withAlertsActions from 'containers/Alert/withAlertActions';
import { Icon, FormattedMessage as T } from 'components'; import { Icon, FormattedMessage as T, Can } from 'components';
import {
InventoryAdjustment,
AbilitySubject,
} from '../../../common/abilityOption';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -26,17 +30,19 @@ function InventoryAdjustmentDetailActionsBar({
}; };
return ( return (
<DashboardActionsBar> <Can I={InventoryAdjustment.Delete} a={AbilitySubject.InventoryAdjustment}>
<NavbarGroup> <DashboardActionsBar>
<Button <NavbarGroup>
className={Classes.MINIMAL} <Button
icon={<Icon icon={'trash-16'} iconSize={16} />} className={Classes.MINIMAL}
text={<T id={'delete'} />} icon={<Icon icon={'trash-16'} iconSize={16} />}
intent={Intent.DANGER} text={<T id={'delete'} />}
onClick={handleDeleteInventoryAdjustment} intent={Intent.DANGER}
/> onClick={handleDeleteInventoryAdjustment}
</NavbarGroup> />
</DashboardActionsBar> </NavbarGroup>
</DashboardActionsBar>
</Can>
); );
} }

View File

@@ -10,11 +10,12 @@ import {
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import { useItemDetailDrawerContext } from './ItemDetailDrawerProvider'; import { useItemDetailDrawerContext } from './ItemDetailDrawerProvider';
import { ItemAbility, AbilitySubject } from '../../../common/abilityOption';
import withAlertsActions from 'containers/Alert/withAlertActions'; import withAlertsActions from 'containers/Alert/withAlertActions';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { Icon, FormattedMessage as T } from 'components'; import { Icon, FormattedMessage as T, Can } from 'components';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -47,20 +48,25 @@ function ItemDetailActionsBar({
return ( return (
<DashboardActionsBar> <DashboardActionsBar>
<NavbarGroup> <NavbarGroup>
<Button <Can I={ItemAbility.Edit} a={AbilitySubject.Item}>
className={Classes.MINIMAL} <Button
icon={<Icon icon="pen-18" />} className={Classes.MINIMAL}
text={<T id={'edit_item'} />} icon={<Icon icon="pen-18" />}
onClick={handleEditItem} text={<T id={'edit_item'} />}
/> onClick={handleEditItem}
<NavbarDivider /> />
<Button
className={Classes.MINIMAL} <NavbarDivider />
icon={<Icon icon={'trash-16'} iconSize={16} />} </Can>
text={<T id={'delete'} />} <Can I={ItemAbility.Delete} a={AbilitySubject.Item}>
intent={Intent.DANGER} <Button
onClick={handleDeleteItem} className={Classes.MINIMAL}
/> icon={<Icon icon={'trash-16'} iconSize={16} />}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={handleDeleteItem}
/>
</Can>
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DashboardActionsBar>
); );

View File

@@ -12,10 +12,14 @@ import {
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import moment from 'moment'; import moment from 'moment';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T, Can } from 'components';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { Icon, Money, If } from 'components'; import { Icon, Money, If } from 'components';
import { isBlank, safeCallback } from 'utils'; import { isBlank, safeCallback } from 'utils';
import {
InventoryAdjustment,
AbilitySubject,
} from '../../common/abilityOption';
/** /**
* Publish accessor * Publish accessor
@@ -102,20 +106,30 @@ export const ActionsMenu = ({
text={intl.get('view_details')} text={intl.get('view_details')}
onClick={safeCallback(onViewDetails, original)} onClick={safeCallback(onViewDetails, original)}
/> />
<MenuDivider />
<If condition={!original.is_published}> <If condition={!original.is_published}>
<MenuItem <MenuDivider />
icon={<Icon icon={'arrow-to-top'} size={16} />} <Can
text={intl.get('publish_adjustment')} I={InventoryAdjustment.Create}
onClick={safeCallback(onPublish, original)} a={AbilitySubject.InventoryAdjustment}
/> >
<MenuItem
icon={<Icon icon={'arrow-to-top'} size={16} />}
text={intl.get('publish_adjustment')}
onClick={safeCallback(onPublish, original)}
/>
</Can>
</If> </If>
<MenuItem <Can
text={intl.get('delete_adjustment')} I={InventoryAdjustment.Delete}
intent={Intent.DANGER} a={AbilitySubject.InventoryAdjustment}
onClick={safeCallback(onDelete, original)} >
icon={<Icon icon="trash-16" iconSize={16} />} <MenuItem
/> text={intl.get('delete_adjustment')}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
icon={<Icon icon="trash-16" iconSize={16} />}
/>
</Can>
</Menu> </Menu>
); );
}; };

View File

@@ -14,6 +14,7 @@ import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import { import {
If, If,
Can,
DashboardActionViewsList, DashboardActionViewsList,
AdvancedFilterPopover, AdvancedFilterPopover,
DashboardFilterButton, DashboardFilterButton,
@@ -30,8 +31,7 @@ import withSettings from '../Settings/withSettings';
import { compose } from 'utils'; import { compose } from 'utils';
import withSettingsActions from '../Settings/withSettingsActions'; import withSettingsActions from '../Settings/withSettingsActions';
import { ItemAbility, AbilitySubject } from '../../common/abilityOption';
import { Can, AbilityContext } from '../../components/Abilities';
/** /**
* Items actions bar. * Items actions bar.
@@ -60,8 +60,6 @@ function ItemsActionsBar({
// Items refresh action. // Items refresh action.
const { refresh } = useRefreshItems(); const { refresh } = useRefreshItems();
const { ability } = React.useContext(AbilityContext);
// History context. // History context.
const history = useHistory(); const history = useHistory();
@@ -106,14 +104,14 @@ function ItemsActionsBar({
/> />
<NavbarDivider /> <NavbarDivider />
{/* <Can I="create" a="Item" ability={ability}> */} <Can I={ItemAbility.Create} a={AbilitySubject.Item}>
<Button <Button
className={Classes.MINIMAL} className={Classes.MINIMAL}
icon={<Icon icon="plus" />} icon={<Icon icon="plus" />}
text={<T id={'new_item'} />} text={<T id={'new_item'} />}
onClick={onClickNewItem} onClick={onClickNewItem}
/> />
{/* </Can> */} </Can>
<AdvancedFilterPopover <AdvancedFilterPopover
advancedFilterProps={{ advancedFilterProps={{
conditions: itemsFilterRoles, conditions: itemsFilterRoles,
@@ -155,11 +153,13 @@ function ItemsActionsBar({
onChange={handleTableRowSizeChange} onChange={handleTableRowSizeChange}
/> />
<NavbarDivider /> <NavbarDivider />
<Switch <Can I={ItemAbility.View} a={AbilitySubject.Item}>
labelElement={<T id={'inactive'} />} <Switch
defaultChecked={itemsInactiveMode} labelElement={<T id={'inactive'} />}
onChange={handleInactiveSwitchChange} defaultChecked={itemsInactiveMode}
/> onChange={handleInactiveSwitchChange}
/>
</Can>
</NavbarGroup> </NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}> <NavbarGroup align={Alignment.RIGHT}>

View File

@@ -12,8 +12,13 @@ import {
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { FormattedMessage as T, Icon, Money, If } from 'components'; import { FormattedMessage as T, Icon, Money, If, Can } from 'components';
import { isBlank, safeCallback } from 'utils'; import { isBlank, safeCallback } from 'utils';
import {
ItemAbility,
InventoryAdjustment,
AbilitySubject,
} from '../../common/abilityOption';
/** /**
* Publish accessor * Publish accessor
@@ -91,43 +96,58 @@ export function ItemsActionMenuList({
onClick={safeCallback(onViewDetails, original)} onClick={safeCallback(onViewDetails, original)}
/> />
<MenuDivider /> <MenuDivider />
<MenuItem <Can I={ItemAbility.Edit} a={AbilitySubject.Item}>
icon={<Icon icon="pen-18" />}
text={intl.get('edit_item')}
onClick={safeCallback(onEditItem, original)}
/>
<MenuItem
icon={<Icon icon="duplicate-16" />}
text={intl.get('duplicate')}
onClick={safeCallback(onDuplicate, original)}
/>
<If condition={original.active}>
<MenuItem <MenuItem
text={intl.get('inactivate_item')} icon={<Icon icon="pen-18" />}
icon={<Icon icon="pause-16" iconSize={16} />} text={intl.get('edit_item')}
onClick={safeCallback(onInactivateItem, original)} onClick={safeCallback(onEditItem, original)}
/> />
</Can>
<Can I={ItemAbility.Create} a={AbilitySubject.Item}>
<MenuItem
icon={<Icon icon="duplicate-16" />}
text={intl.get('duplicate')}
onClick={safeCallback(onDuplicate, original)}
/>
</Can>
<If condition={original.active}>
<Can I={ItemAbility.View} a={AbilitySubject.Item}>
<MenuItem
text={intl.get('inactivate_item')}
icon={<Icon icon="pause-16" iconSize={16} />}
onClick={safeCallback(onInactivateItem, original)}
/>
</Can>
</If> </If>
<If condition={!original.active}> <If condition={!original.active}>
<MenuItem <Can I={ItemAbility.View} a={AbilitySubject.Item}>
text={intl.get('activate_item')} <MenuItem
icon={<Icon icon="play-16" iconSize={16} />} text={intl.get('activate_item')}
onClick={safeCallback(onActivateItem, original)} icon={<Icon icon="play-16" iconSize={16} />}
/> onClick={safeCallback(onActivateItem, original)}
/>
</Can>
</If> </If>
<If condition={original.type === 'inventory'}> <If condition={original.type === 'inventory'}>
<MenuItem <Can
text={intl.get('make_adjustment')} I={InventoryAdjustment.Create}
icon={<Icon icon={'swap-vert'} iconSize={16} />} a={AbilitySubject.InventoryAdjustment}
onClick={safeCallback(onMakeAdjustment, original)} >
/> <MenuItem
text={intl.get('make_adjustment')}
icon={<Icon icon={'swap-vert'} iconSize={16} />}
onClick={safeCallback(onMakeAdjustment, original)}
/>
</Can>
</If> </If>
<MenuItem <Can I={ItemAbility.Delete} a={AbilitySubject.Item}>
text={intl.get('delete_item')} <MenuItem
icon={<Icon icon="trash-16" iconSize={16} />} text={intl.get('delete_item')}
onClick={safeCallback(onDeleteItem, original)} icon={<Icon icon="trash-16" iconSize={16} />}
intent={Intent.DANGER} onClick={safeCallback(onDeleteItem, original)}
/> intent={Intent.DANGER}
/>
</Can>
</Menu> </Menu>
); );
} }