Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop

This commit is contained in:
elforjani13
2021-12-22 20:43:07 +02:00
14 changed files with 913 additions and 181 deletions

View File

@@ -17,6 +17,8 @@ export const AbilitySubject = {
Preferences: 'Preferences', Preferences: 'Preferences',
ExchangeRate: 'ExchangeRate', ExchangeRate: 'ExchangeRate',
SubscriptionBilling: 'SubscriptionBilling', SubscriptionBilling: 'SubscriptionBilling',
CreditNote: 'CreditNote',
VendorCredit: 'VendorCredit',
}; };
export const ItemAction = { export const ItemAction = {
@@ -66,6 +68,21 @@ export const PaymentReceiveAction = {
NotifyBySms: 'NotifyBySms', NotifyBySms: 'NotifyBySms',
}; };
export const CreditNoteAction = {
View: 'View',
Create: 'Create',
Edit: 'Edit',
Delete: 'Delete',
Refund: 'Refund'
};
export const VendorCreditAction = {
View: 'View',
Create: 'Create',
Edit: 'Edit',
Delete: 'Delete',
Refund: 'Refund'
};
export const BillAction = { export const BillAction = {
View: 'View', View: 'View',
Create: 'Create', Create: 'Create',

View File

@@ -0,0 +1,288 @@
import {
AbilitySubject,
AccountAction,
BillAction,
CreditNoteAction,
CustomerAction,
ExpenseAction,
ItemAction,
ManualJournalAction,
PaymentMadeAction,
PaymentReceiveAction,
ReportsAction,
SaleEstimateAction,
SaleInvoiceAction,
SaleReceiptAction,
VendorAction,
VendorCreditAction
} from './abilityOption';
export const ModulePermissionsStyle = {
Columns: 'columns',
Vertical: 'vertical',
};
const PermissionColumn = {
View: 'view',
Create: 'create',
Delete: 'delete',
Edit: 'edit'
}
export const permissions = [
{
label: 'Items & Inventory',
type: ModulePermissionsStyle.Columns,
serviceFullAccess: true,
moduleFullAccess: true,
columns: [
{ label: 'View', key: 'view' },
{ label: 'Create', key: 'create' },
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' },
],
services: [
{
label: 'Items',
subject: AbilitySubject.Item,
permissions: [
{ label: 'View', key: ItemAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: ItemAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: ItemAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: ItemAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
{
label: 'Inventory adjustments',
subject: AbilitySubject.InventoryAdjustment,
permissions: [
{ label: 'View', key: ItemAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: ItemAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: ItemAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: ItemAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
],
},
{
label: 'Contacts',
type: ModulePermissionsStyle.Columns,
serviceFullAccess: true,
moduleFullAccess: true,
columns: [
{ label: 'View', key: 'view' },
{ label: 'Create', key: 'create' },
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' },
],
services: [
{
label: 'Customers',
subject: AbilitySubject.Customer,
permissions: [
{ label: 'View', key: CustomerAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: CustomerAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: CustomerAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: CustomerAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
{
label: 'Vendors',
subject: AbilitySubject.Customer,
permissions: [
{ label: 'View', key: VendorAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: VendorAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: VendorAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: VendorAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
]
},
{
label: 'Sales',
type: ModulePermissionsStyle.Columns,
serviceFullAccess: true,
moduleFullAccess: true,
columns: [
{ label: 'View', key: 'view' },
{ label: 'Create', key: 'create' },
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' },
],
services: [
{
label: 'Sale Invoice',
subject: AbilitySubject.Invoice,
permissions: [
{ label: 'View', key: SaleInvoiceAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: SaleInvoiceAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: SaleInvoiceAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: SaleInvoiceAction.Delete, relatedColumn: PermissionColumn.Delete },
{ label: 'Written-off invoice', key: SaleInvoiceAction.Writeoff }
],
},
{
label: 'Sale Estimate',
subject: AbilitySubject.Estimate,
permissions: [
{ label: 'View', key: SaleEstimateAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: SaleEstimateAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: SaleEstimateAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: SaleEstimateAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
{
label: 'Sale Receipt',
subject: AbilitySubject.Receipt,
permissions: [
{ label: 'View', key: SaleReceiptAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: SaleReceiptAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: SaleReceiptAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: SaleReceiptAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
{
label: 'Credit note',
subject: AbilitySubject.CreditNote,
permissions: [
{ label: 'View', key: CreditNoteAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: CreditNoteAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: CreditNoteAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: CreditNoteAction.Delete, relatedColumn: PermissionColumn.Delete },
{ label: 'Refund credit note', key: CreditNoteAction.Refund }
],
},
{
label: 'Payment Receive',
subject: AbilitySubject.PaymentReceive,
permissions: [
{ label: 'View', key: PaymentReceiveAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: PaymentReceiveAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: PaymentReceiveAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: PaymentReceiveAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
]
},
{
label: 'Purchases',
type: ModulePermissionsStyle.Columns,
serviceFullAccess: true,
moduleFullAccess: true,
columns: [
{ label: 'View', key: 'view' },
{ label: 'Create', key: 'create' },
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' },
],
services: [
{
label: 'Bills',
subject: AbilitySubject.Bill,
permissions: [
{ label: 'View', key: BillAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: BillAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: BillAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: BillAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
{
label: 'Vendor Credits',
subject: AbilitySubject.VendorCredit,
permissions: [
{ label: 'View', key: VendorCreditAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: VendorCreditAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: VendorCreditAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: VendorCreditAction.Delete, relatedColumn: PermissionColumn.Delete },
{ label: 'Refund vendor credit', key: VendorCreditAction.Refund }
],
},
{
label: 'Payment Made',
subject: AbilitySubject.PaymentMade,
permissions: [
{ label: 'View', key: PaymentMadeAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: PaymentMadeAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: PaymentMadeAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: PaymentMadeAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
]
},
{
label: 'Financial Accounting',
type: ModulePermissionsStyle.Columns,
serviceFullAccess: true,
moduleFullAccess: true,
columns: [
{ label: 'View', key: 'view' },
{ label: 'Create', key: 'create' },
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' },
],
services: [
{
label: 'Manual Journals',
subject: AbilitySubject.ManualJournal,
permissions: [
{ label: 'View', key: ManualJournalAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: ManualJournalAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: ManualJournalAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: ManualJournalAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
{
label: 'Chart of Accounts',
subject: AbilitySubject.Account,
permissions: [
{ label: 'View', key: AccountAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: AccountAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: AccountAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: AccountAction.Delete, relatedColumn: PermissionColumn.Delete },
{ label: 'Transactions locking', key: AccountAction.TransactionsLocking },
],
},
{
label: 'Expenses',
subject: AbilitySubject.Expense,
permissions: [
{ label: 'View', key: ExpenseAction.View, relatedColumn: PermissionColumn.View },
{ label: 'Create', key: ExpenseAction.Create, relatedColumn: PermissionColumn.Create },
{ label: 'Edit', key: ExpenseAction.Edit, relatedColumn: PermissionColumn.Edit },
{ label: 'Delete', key: ExpenseAction.Delete, relatedColumn: PermissionColumn.Delete },
],
},
]
},
{
label: 'Financial Reports',
type: ModulePermissionsStyle.Vertical,
serviceFullAccess: true,
moduleFullAccess: true,
services: [
{
label: 'Financial reprots',
subject: AbilitySubject.Report,
permissions: [
{ label: 'Balance sheet', key: ReportsAction.READ_BALANCE_SHEET },
{ label: 'Trial Balance sheet', key: ReportsAction.READ_TRIAL_BALANCE_SHEET },
{ label: 'Profit & Loss sheet', key: ReportsAction.READ_PROFIT_LOSS },
{ label: 'Cash flow sheet', key: ReportsAction.READ_CASHFLOW },
{ label: 'Journal sheet', key: ReportsAction.READ_JOURNAL },
{ label: 'General ledger', key: ReportsAction.READ_GENERAL_LEDGET },
{ label: 'A/R Aging Summary report', key: ReportsAction.READ_AR_AGING_SUMMARY },
{ label: 'A/P Aging Summary report', key: ReportsAction.READ_AP_AGING_SUMMARY },
{ label: 'Purchases by items', key: ReportsAction.READ_PURCHASES_BY_ITEMS },
{ label: 'Sales by items', key: ReportsAction.READ_SALES_BY_ITEMS },
{ label: 'Customers transactions', key: ReportsAction.READ_CUSTOMERS_TRANSACTIONS },
{ label: 'Vendors transactions', key: ReportsAction.READ_VENDORS_TRANSACTIONS },
{ label: 'Customers summary balance', key: ReportsAction.READ_CUSTOMERS_SUMMARY_BALANCE },
{ label: 'Vendors summary balance', key: ReportsAction.READ_VENDORS_SUMMARY_BALANCE },
{ label: 'Inventory valuation summary', key: ReportsAction.READ_INVENTORY_VALUATION_SUMMARY },
{ label: 'Inventory items details', key: ReportsAction.READ_INVENTORY_ITEM_DETAILS },
{ label: 'Cashflow account transactions', key: ReportsAction.READ_CASHFLOW_ACCOUNT_TRANSACTION },
],
},
],
}
];

View File

@@ -1,6 +1,8 @@
import React from 'react'; import React from 'react';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import classNames from 'classnames'; import classNames from 'classnames';
import * as R from 'ramda';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import PreferencesTopbar from 'components/Preferences/PreferencesTopbar'; import PreferencesTopbar from 'components/Preferences/PreferencesTopbar';
@@ -8,18 +10,28 @@ import PreferencesContentRoute from 'components/Preferences/PreferencesContentRo
import DashboardErrorBoundary from 'components/Dashboard/DashboardErrorBoundary'; import DashboardErrorBoundary from 'components/Dashboard/DashboardErrorBoundary';
import PreferencesSidebar from 'components/Preferences/PreferencesSidebar'; import PreferencesSidebar from 'components/Preferences/PreferencesSidebar';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import 'style/pages/Preferences/Page.scss'; import 'style/pages/Preferences/Page.scss';
/** /**
* Preferences page. * Preferences page.
*/ */
export default function PreferencesPage() { function PreferencesPage({ toggleSidebarExpand }) {
// Shrink the dashboard sidebar once open application preferences page.
React.useEffect(() => {
toggleSidebarExpand(false);
}, [toggleSidebarExpand]);
return ( return (
<ErrorBoundary FallbackComponent={DashboardErrorBoundary}> <ErrorBoundary FallbackComponent={DashboardErrorBoundary}>
<div id={'dashboard'} className={classNames( <div
CLASSES.DASHBOARD_CONTENT, id={'dashboard'}
CLASSES.DASHBOARD_CONTENT_PREFERENCES, className={classNames(
)}> CLASSES.DASHBOARD_CONTENT,
CLASSES.DASHBOARD_CONTENT_PREFERENCES,
)}
>
<div className={classNames(CLASSES.PREFERENCES_PAGE)}> <div className={classNames(CLASSES.PREFERENCES_PAGE)}>
<PreferencesSidebar /> <PreferencesSidebar />
@@ -32,3 +44,5 @@ export default function PreferencesPage() {
</ErrorBoundary> </ErrorBoundary>
); );
} }
export default R.compose(withDashboardActions)(PreferencesPage);

View File

@@ -0,0 +1,50 @@
import React from 'react';
import { useFormikContext } from 'formik';
import styled from 'styled-components';
import { Intent, Button } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { FormattedMessage as T } from 'components';
/**
* Role form floating actions.
* @returns {React.JSX}
*/
export function RoleFormFloatingActions() {
const { isSubmitting } = useFormikContext();
const history = useHistory();
const handleCloseClick = () => {
history.go(-1);
};
return (
<RoleFormFloatingActionsRoot>
<Button
intent={Intent.PRIMARY}
loading={isSubmitting}
type="submit"
style={{ minWidth: '90px' }}
>
<T id={'save'} />
</Button>
<Button onClick={handleCloseClick} disabled={isSubmitting}>
<T id={'cancel'} />
</Button>
</RoleFormFloatingActionsRoot>
);
}
const RoleFormFloatingActionsRoot = styled.div`
position: fixed;
bottom: 0;
width: 100%;
background: #fff;
padding: 14px 18px;
border-top: 1px solid #d2dde2;
box-shadow: 0px -1px 4px 0px rgb(0 0 0 / 5%);
.bp3-button {
margin-right: 10px;
}
`;

View File

@@ -1,37 +1,27 @@
import React from 'react'; import React from 'react';
import { useHistory } from 'react-router-dom'; import { ErrorMessage, FastField, Form } from 'formik';
import { ErrorMessage, FastField, Form, useFormikContext } from 'formik'; import { FormGroup, InputGroup, TextArea } from '@blueprintjs/core';
import {
Button,
FormGroup,
InputGroup,
Intent,
TextArea,
} from '@blueprintjs/core';
import { inputIntent } from 'utils'; import { inputIntent } from 'utils';
import { FormattedMessage as T, FieldRequiredHint } from 'components'; import { FormattedMessage as T, FieldRequiredHint, Card } from 'components';
import { useAutofocus } from 'hooks'; import { useAutofocus } from 'hooks';
import { RolesPermissionList } from './components'; import { RolesPermissionList } from './components';
import { RoleFormFloatingActions } from './RoleFormFloatingActions';
/** /**
* Preferences - Roles Form content. * Role form header.
* @returns {React.JSX}
*/ */
export default function RolesFormContent() { function RoleFormHeader() {
const history = useHistory();
const { isSubmitting, values } = useFormikContext();
const roleNameFieldRef = useAutofocus(); const roleNameFieldRef = useAutofocus();
const handleCloseClick = () => {
history.go(-1);
};
return ( return (
<Form> <Card>
{/* ---------- name ---------- */} {/* ---------- name ---------- */}
<FastField name={'role_name'}> <FastField name={'role_name'}>
{({ field, meta: { error, touched } }) => ( {({ field, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'name'} />} label={<strong><T id={'role_name'} /></strong>}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
className={'form-group--name'} className={'form-group--name'}
intent={inputIntent({ error, touched })} intent={inputIntent({ error, touched })}
@@ -57,20 +47,28 @@ export default function RolesFormContent() {
helperText={<ErrorMessage name={'role_description'} />} helperText={<ErrorMessage name={'role_description'} />}
inline={true} inline={true}
> >
<TextArea growVertically={true} height={280} {...field} /> <TextArea
growVertically={true}
height={280}
{...field}
placeholder="Max. 500 characters"
/>
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
<RolesPermissionList /> </Card>
);
}
<div className={'card__footer'}> /**
<Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit"> * Preferences - Roles Form content.
<T id={'save'} /> */
</Button> export default function RolesFormContent() {
<Button onClick={handleCloseClick} disabled={isSubmitting}> return (
<T id={'cancel'} /> <Form>
</Button> <RoleFormHeader />
</div> <RolesPermissionList />
<RoleFormFloatingActions />
</Form> </Form>
); );
} }

View File

@@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import _, { isArray } from 'lodash';
import { import {
useCreateRolePermissionSchema, useCreateRolePermissionSchema,
@@ -10,7 +9,6 @@ import {
useRolePermission, useRolePermission,
} from 'hooks/query'; } from 'hooks/query';
import PreferencesPageLoader from '../../../PreferencesPageLoader'; import PreferencesPageLoader from '../../../PreferencesPageLoader';
import { transformToObject } from './utils';
const RolesFormContext = React.createContext(); const RolesFormContext = React.createContext();
@@ -32,10 +30,12 @@ function RolesFormProvider({ roleId, ...props }) {
isFetching: isPermissionsSchemaFetching, isFetching: isPermissionsSchemaFetching,
} = usePermissionsSchema(); } = usePermissionsSchema();
const { data: role, isLoading: isPermissionLoading } = const { data: role, isLoading: isPermissionLoading } = useRolePermission(
useRolePermission(roleId, { roleId,
{
enabled: !!roleId, enabled: !!roleId,
}); },
);
// Detarmines whether the new or edit mode. // Detarmines whether the new or edit mode.
const isNewMode = !roleId; const isNewMode = !roleId;
@@ -59,13 +59,11 @@ function RolesFormProvider({ roleId, ...props }) {
CLASSES.PREFERENCES_PAGE_INSIDE_CONTENT_ROLES_FORM, CLASSES.PREFERENCES_PAGE_INSIDE_CONTENT_ROLES_FORM,
)} )}
> >
<div className={classNames(CLASSES.CARD)}> {isPermissionsSchemaLoading || isPermissionLoading ? (
{isPermissionsSchemaLoading || isPermissionLoading ? ( <PreferencesPageLoader />
<PreferencesPageLoader /> ) : (
) : ( <RolesFormContext.Provider value={provider} {...props} />
<RolesFormContext.Provider value={provider} {...props} /> )}
)}
</div>
</div> </div>
); );
} }

View File

@@ -1,148 +1,496 @@
import React from 'react'; import React from 'react';
import { Checkbox } from '@blueprintjs/core'; import { Checkbox, Switch, Popover } from '@blueprintjs/core';
import styled from 'styled-components'; import styled from 'styled-components';
import { castArray } from 'lodash'; import { FastField } from 'formik';
import { FastField, useFormikContext } from 'formik'; import { permissions, ModulePermissionsStyle } from 'common/permissionsSchema';
import { useRolesFormContext } from './RolesFormProvider'; import { Card, If, ButtonLink, Choose } from 'components';
import {
getSerivceColumnPermission,
getServiceExtraPermissions,
} from './utils';
const RoleLabelCheckbox = ({ subject, label, description }) => ( // Module permissions context.
<> const ModulePermissionsContext = React.createContext();
<LabelCheckbox> const ModuleServiceContext = React.createContext();
{/*------------- subject checbox ------------- */}
<FastField name={subject} type="checkbox">
{({ form: { setFieldValue, values }, field }) => (
<Checkbox
className={'block'}
inline={true}
label={label}
name={subject}
/>
)}
</FastField>
<p>{description}</p>
</LabelCheckbox>
</>
);
const AbilitiesList = ({ subject, abilities }) => { /**
* Retrieves the module permissions provider.
* @returns {React.JSX}
*/
const useModulePermissionsProvider = () =>
React.useContext(ModulePermissionsContext);
/**
* Module permissions service context provider.
*/
const useModulePermissionsServiceProvider = () =>
React.useContext(ModuleServiceContext);
/**
* Module permissions context state provider.
* @returns {React.JSX}
*/
function ModulePermissionsProvider({ module, children }) {
return ( return (
<AbilitieList> <ModulePermissionsContext.Provider value={{ module }}>
{abilities?.map(({ key, label }) => ( {children}
<FastField name={`permissions.${subject}/${key}`} type="checkbox"> </ModulePermissionsContext.Provider>
);
}
/**
* Module permissions service context state provider.
* @returns {React.JSX}
*/
function ModulePermissionsServiceProvider({ service, children }) {
return (
<ModuleServiceContext.Provider value={{ service }}>
{children}
</ModuleServiceContext.Provider>
);
}
/**
* Permissions body columns.
* @returns {React.JSX}
*/
function PermissionBodyColumn({ column }) {
// Module permssions service context.
const { service } = useModulePermissionsServiceProvider();
// Retrieve the related permission of the given column key.
const permission = getSerivceColumnPermission(service, column.key);
// Display empty cell if the current column key has no related permissions.
if (!permission) {
return <td class={'permission-checkbox'}></td>;
}
return (
<td class={'permission-checkbox'}>
<FastField
name={`permissions.${service.subject}/${permission.key}`}
type="checkbox"
>
{({ field }) => <PermissionCheckbox inline={true} {...field} />}
</FastField>
</td>
);
}
/**
*
* @returns {React.JSX}
*/
function ModulePermissionsTableColumns({ columns }) {
return columns.map((column) => <PermissionBodyColumn column={column} />);
}
/**
* Module columns permissions extra permissions popover.
* @returns {React.JSX}
*/
function ModuleExtraPermissionsPopover() {
const { service } = useModulePermissionsServiceProvider();
// Retrieve the extra permissions of the given service.
const extraPermissions = getServiceExtraPermissions(service);
return (
<Popover>
<MorePermissionsLink>More Permissions</MorePermissionsLink>
<ExtraPermissionsRoot>
{extraPermissions.map((permission) => (
<FastField
name={`permissions.${service.subject}/${permission.key}`}
type="checkbox"
>
{({ form: { setFieldValue, values }, field }) => (
<PermissionCheckbox
inline={true}
label={permission.label}
{...field}
/>
)}
</FastField>
))}
</ExtraPermissionsRoot>
</Popover>
);
}
/**
* Module permissions extra permissions.
* @returns {React.JSX}
*/
function ModulePermissionExtraPermissions() {
const { service } = useModulePermissionsServiceProvider();
// Retrieve the extra permissions of the given service.
const extraPermissions = getServiceExtraPermissions(service);
return (
<td>
<If condition={extraPermissions.length > 0}>
<ModuleExtraPermissionsPopover />
</If>
</td>
);
}
/**
* Module permissions table head.
* @returns {React.JSX}
*/
function ModulePermissionsTableHead() {
const {
module: { serviceFullAccess, columns },
} = useModulePermissionsProvider();
return (
<thead>
<tr>
<th></th>
<If condition={serviceFullAccess}>
<th class={'full'}>Full Access</th>
</If>
{columns.map((column) => (
<th class={'permission'}>{column.label}</th>
))}
<th></th>
</tr>
</thead>
);
}
/**
* Module permissions service full access.
* @returns {React.JSX}
*/
function ModulePermissionsServiceFullAccess() {
// Module permissions provider.
const { module } = useModulePermissionsProvider();
// Module service provider.
const { service } = useModulePermissionsServiceProvider();
return (
<If condition={module.serviceFullAccess}>
<td class="full-access-permission">
<FastField
name={`serviceFullAccess.${service.subject}`}
type="checkbox"
>
{({ form: { setFieldValue, values }, field }) => ( {({ form: { setFieldValue, values }, field }) => (
<Checkbox inline={true} label={label} {...field} /> <PermissionCheckbox inline={true} />
)} )}
</FastField> </FastField>
))} </td>
</AbilitieList> </If>
); );
}; }
const ExtraAbilitiesList = ({ subject, extraAbilities }) => { /**
return extraAbilities?.map(({ key, label }) => ( * Module permissions table body.
<AbilitieList> * @returns {React.JSX}
<FastField name={`permissions.${subject}/${key}`} type="checkbox"> */
{({ form: { setFieldValue, values }, field }) => ( function ModulePermissionsTableBody() {
<Checkbox inline={true} label={label} {...field} /> const {
)} module: { services, columns },
</FastField> } = useModulePermissionsProvider();
</AbilitieList>
));
};
export const RolesPermissionList = () => {
const { permissionsSchema } = useRolesFormContext();
return ( return (
<GroupList> <tbody>
<BoxedGroupList> {services.map((service) => (
{permissionsSchema.map( <ModulePermissionsServiceProvider service={service}>
({ <tr>
subject, <td className="service-label">{service.label} </td>
subject_label,
description,
abilities,
extra_abilities,
}) => {
const extraAbilitiesList = Array.isArray(extra_abilities)
? extra_abilities
: [];
const abilitiesList = castArray(abilities) ? abilities : []; <ModulePermissionsServiceFullAccess />
<ModulePermissionsTableColumns columns={columns} />
<ModulePermissionExtraPermissions />
</tr>
</ModulePermissionsServiceProvider>
))}
</tbody>
);
}
return ( /**
<React.Fragment> * Module permissions table.
<RoleList> * @returns {React.JSX}
<RoleLabelCheckbox */
subject={subject} function ModulePermissionsTable() {
label={subject_label} return (
description={description} <ModulePermissionsTableRoot>
/> <ModulePermissionsTableHead />
<ModulePermissionsTableBody />
</ModulePermissionsTableRoot>
);
}
<AbilitiesList subject={subject} abilities={abilitiesList} /> /**
<ExtraAbilitiesList * Module vertical table cells.
subject={subject} * @returns {React.JSX}
extraAbilities={extraAbilitiesList} */
/> function ModuleVerticalTableCells() {
</RoleList> const { service } = useModulePermissionsServiceProvider();
</React.Fragment>
); return (
}, <td class={'permissions'}>
)} {service.permissions.map((permission) => (
</BoxedGroupList> <div>
</GroupList> <FastField
name={`permissions.${service.subject}/${permission.key}`}
type="checkbox"
>
{({ form: { setFieldValue, values }, field }) => (
<PermissionCheckbox
inline={true}
label={permission.label}
{...field}
/>
)}
</FastField>
</div>
))}
</td>
);
}
/**
* Module permissions vertical services.
* @returns {React.JSX}
*/
function ModulePermissionsVerticalServices() {
const { module } = useModulePermissionsProvider();
return (
<ModulePermissionsVerticalServicesRoot>
<ModulePermissionsVerticalTable>
<tbody>
{module.services.map((service) => (
<ModulePermissionsServiceProvider service={service}>
<tr>
<td class={'service-label'}>{service.label} </td>
<ModuleVerticalTableCells />
</tr>
</ModulePermissionsServiceProvider>
))}
</tbody>
</ModulePermissionsVerticalTable>
</ModulePermissionsVerticalServicesRoot>
);
}
/**
* Module permissions body.
* @returns {React.JSX}
*/
function ModulePermissionsBody() {
const { module } = useModulePermissionsProvider();
return (
<ModulePermissionBodyRoot>
<Choose>
<Choose.When
condition={module.type === ModulePermissionsStyle.Vertical}
>
<ModulePermissionsVerticalServices />
</Choose.When>
<Choose.When condition={module.type === ModulePermissionsStyle.Columns}>
<ModulePermissionsTable />
</Choose.When>
</Choose>
</ModulePermissionBodyRoot>
);
}
/**
* Permissions module.
* @returns {React.JSX}
*/
function ModulePermissions({ module }) {
return (
<ModulePermissionsRoot>
<ModulePermissionsProvider module={module}>
<ModulePermissionHead>
<ModulePermissionTitle>{module.label} </ModulePermissionTitle>
<If condition={module.moduleFullAccess}>
<ModulePermissionFullControlRoot>
<Switch />
</ModulePermissionFullControlRoot>
</If>
</ModulePermissionHead>
<ModulePermissionsBody />
</ModulePermissionsProvider>
</ModulePermissionsRoot>
);
}
/**
* Permissions modules list.
* @return {React.JSX}
*/
export const RolesPermissionList = () => {
return (
<ModulesPermission>
{permissions.map((module) => (
<ModulePermissions module={module} />
))}
</ModulesPermission>
); );
}; };
const GroupList = styled.div` const PermissionCheckbox = styled(Checkbox)`
list-style: none; &.bp3-control.bp3-checkbox .bp3-control-indicator {
border: 1px solid #d2dce2; border-radius: 2px;
border-radius: 6px; border-color: #555;
font-size: 13px;
ul:first-child > li:last-child { &,
border-bottom: 0; &:before {
border-top: 0; width: 15px;
height: 15px;
}
} }
`; `;
const BoxedGroupList = styled.ul` const ModulesPermission = styled.div``;
margin: 0;
list-style: none; const ModulePermissionsRoot = styled(Card)`
padding: 0 !important;
`; `;
const RoleList = styled.li` const ModulePermissionHead = styled.div`
display: block; border-bottom: 1px solid #d9d9d9;
padding: 5px 10px; height: 38px;
margin: 0; padding: 0 15px;
line-height: 20px; display: flex;
border-bottom: 1px solid #e0e0e0;
`; `;
const LabelCheckbox = styled.label` const ModulePermissionTitle = styled.div`
> * { font-weight: 500;
display: inline-block; font-size: 16px;
} line-height: 38px;
.block { color: #878787;
width: 220px; `;
padding: 2px 0;
font-weight: 500; const ModulePermissionFullControlRoot = styled.div`
margin-left: auto;
display: flex;
.bp3-switch {
margin: auto;
} }
`; `;
const AbilitieList = styled.ul` const ModulePermissionBodyRoot = styled.div``;
list-style: none;
/* margin-left: 12px; // 10px */
margin: 0px 10px 0px;
> li { const ModulePermissionsTableRoot = styled.table`
display: inline-block; border-spacing: 0;
margin-top: 3px;
thead {
tr th {
font-weight: 400;
vertical-align: top;
&.full,
&.permission {
min-width: 70px;
}
&.full {
background-color: #fcfcfc;
}
}
}
thead,
tbody {
tr td,
tr th {
border-bottom: 1px solid #eee;
border-left: 1px solid #eee;
padding: 10px;
&:first-of-type {
border-left: 0;
}
}
tr:last-of-type td {
border-bottom: 0;
}
tr td:last-of-type,
tr th:last-of-type {
width: 100%;
}
}
tbody {
tr td.service-label {
min-width: 250px;
}
tr td {
.bp3-control.bp3-inline {
margin: 0;
}
&.full-access-permission {
background-color: #fcfcfc;
}
&.full-access-permission,
&.permission-checkbox {
text-align: center;
}
}
} }
`; `;
const AbilitiesChildList = styled.li` const MorePermissionsLink = styled(ButtonLink)`
display: inline-block; font-size: 12px;
margin-top: 3px; `;
const ExtraPermissionsRoot = styled.div`
display: flex;
flex-direction: column;
padding: 15px;
`;
const ModulePermissionsVerticalServicesRoot = styled.div``;
const ModulePermissionsVerticalTable = styled.table`
border-spacing: 0;
tbody {
tr td {
padding: 10px;
vertical-align: top;
border-left: 1px solid #eee;
border-bottom: 1px solid #eee;
&.service-label {
min-width: 250px;
color: #333;
}
&:first-of-type {
border-left: 0;
}
&.permissions {
width: 100%;
}
}
tr:last-of-type td {
border-bottom: 0;
}
}
`; `;

View File

@@ -51,3 +51,15 @@ export const getNewRoleInitialValues = (schema) => {
), ),
}; };
}; };
export function getSerivceColumnPermission(service, columnKey) {
return service.permissions.find((permission) => {
return permission.relatedColumn === columnKey;
});
}
export function getServiceExtraPermissions(service) {
return service.permissions.filter((permission) => {
return !permission.relatedColumn;
});
}

View File

@@ -1653,5 +1653,6 @@
"overview": "Overview", "overview": "Overview",
"transactions": "Transactions", "transactions": "Transactions",
"item.drawer_transactions_by": "Transactions by:", "item.drawer_transactions_by": "Transactions by:",
"item.drawer_quantity_sold": "Quantity Sold" "item.drawer_quantity_sold": "Quantity Sold",
"role_name": "Role name"
} }

View File

@@ -11,6 +11,7 @@
// Objects // Objects
@import 'objects/form'; @import 'objects/form';
@import 'objects/switch';
@import 'objects/typography'; @import 'objects/typography';
@import 'objects/buttons'; @import 'objects/buttons';
@import 'objects/Bigcapital'; @import 'objects/Bigcapital';

View File

@@ -0,0 +1,8 @@
.bp3-control.bp3-switch {
.bp3-control-indicator {
&:before {
box-shadow: none;
}
}
}

View File

@@ -33,6 +33,8 @@
} }
} }
&__inside-content { &__inside-content {
overflow: auto;
.#{$ns}-tab-list { .#{$ns}-tab-list {
border-bottom: 1px solid #e5e5e5; border-bottom: 1px solid #e5e5e5;
padding-left: 15px; padding-left: 15px;

View File

@@ -1,6 +1,8 @@
// Roles Form page // Roles Form page
//--------------------------------- //---------------------------------
.preferences-page__inside-content--roles-form { .preferences-page__inside-content--roles-form {
padding-bottom: 60px;
.card { .card {
padding: 25px; padding: 25px;
@@ -20,17 +22,21 @@
} }
.bp3-form-group { .bp3-form-group {
max-width: 500px; max-width: 600px;
margin-bottom: 14px; margin-bottom: 14px;
&.bp3-inline { &.bp3-inline {
.bp3-label { .bp3-label {
min-width: 100px; min-width: 150px;
} }
} }
.bp3-form-content { .bp3-form-content {
width: 100%; width: 100%;
} }
&:last-of-type{
margin-bottom: 0;
}
} }
.form-group--description { .form-group--description {
textarea { textarea {
@@ -39,20 +45,4 @@
font-size: 14px; font-size: 14px;
} }
} }
.bp3-control.bp3-checkbox {
.bp3-control-indicator {
border: 1px solid #c2c2c2;
cursor: auto;
&,
&:hover {
height: 15px;
width: 15px;
}
&:before {
width: 15px;
height: 15px;
}
}
}
} }

View File

@@ -3,7 +3,7 @@
// Preferences sidebar. // Preferences sidebar.
// ----------------------------- // -----------------------------
.preferences-sidebar { .preferences-sidebar {
background: #e5eaee; background: #eaeef6;
border-right: 1px solid #c6d0d9; border-right: 1px solid #c6d0d9;
min-width: 220px; min-width: 220px;
max-width: 220px; max-width: 220px;
@@ -13,13 +13,17 @@
&__wrapper { &__wrapper {
height: 100%; height: 100%;
} }
.ScrollbarsCustom-Track { .ScrollbarsCustom-Track {
&.ScrollbarsCustom-TrackY, &.ScrollbarsCustom-TrackY,
&.ScrollbarsCustom-TrackX { &.ScrollbarsCustom-TrackX {
background: rgba(0, 0, 0, 0); background: rgba(0, 0, 0, 0);
} }
} }
.ScrollbarsCustom-Thumb { .ScrollbarsCustom-Thumb {
&.ScrollbarsCustom-ThumbX, &.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY { &.ScrollbarsCustom-ThumbY {
background: rgba(0, 0, 0, 0); background: rgba(0, 0, 0, 0);
@@ -28,6 +32,7 @@
&:hover { &:hover {
.ScrollbarsCustom-Thumb { .ScrollbarsCustom-Thumb {
&.ScrollbarsCustom-ThumbX, &.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY { &.ScrollbarsCustom-ThumbY {
background: rgba(0, 0, 0, 0.15); background: rgba(0, 0, 0, 0.15);
@@ -68,4 +73,4 @@
} }
} }
} }
} }