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',
ExchangeRate: 'ExchangeRate',
SubscriptionBilling: 'SubscriptionBilling',
CreditNote: 'CreditNote',
VendorCredit: 'VendorCredit',
};
export const ItemAction = {
@@ -66,6 +68,21 @@ export const PaymentReceiveAction = {
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 = {
View: 'View',
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 { ErrorBoundary } from 'react-error-boundary';
import classNames from 'classnames';
import * as R from 'ramda';
import { CLASSES } from 'common/classes';
import PreferencesTopbar from 'components/Preferences/PreferencesTopbar';
@@ -8,18 +10,28 @@ import PreferencesContentRoute from 'components/Preferences/PreferencesContentRo
import DashboardErrorBoundary from 'components/Dashboard/DashboardErrorBoundary';
import PreferencesSidebar from 'components/Preferences/PreferencesSidebar';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import 'style/pages/Preferences/Page.scss';
/**
* Preferences page.
*/
export default function PreferencesPage() {
function PreferencesPage({ toggleSidebarExpand }) {
// Shrink the dashboard sidebar once open application preferences page.
React.useEffect(() => {
toggleSidebarExpand(false);
}, [toggleSidebarExpand]);
return (
<ErrorBoundary FallbackComponent={DashboardErrorBoundary}>
<div id={'dashboard'} className={classNames(
CLASSES.DASHBOARD_CONTENT,
CLASSES.DASHBOARD_CONTENT_PREFERENCES,
)}>
<div
id={'dashboard'}
className={classNames(
CLASSES.DASHBOARD_CONTENT,
CLASSES.DASHBOARD_CONTENT_PREFERENCES,
)}
>
<div className={classNames(CLASSES.PREFERENCES_PAGE)}>
<PreferencesSidebar />
@@ -32,3 +44,5 @@ export default function PreferencesPage() {
</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 { useHistory } from 'react-router-dom';
import { ErrorMessage, FastField, Form, useFormikContext } from 'formik';
import {
Button,
FormGroup,
InputGroup,
Intent,
TextArea,
} from '@blueprintjs/core';
import { ErrorMessage, FastField, Form } from 'formik';
import { FormGroup, InputGroup, TextArea } from '@blueprintjs/core';
import { inputIntent } from 'utils';
import { FormattedMessage as T, FieldRequiredHint } from 'components';
import { FormattedMessage as T, FieldRequiredHint, Card } from 'components';
import { useAutofocus } from 'hooks';
import { RolesPermissionList } from './components';
import { RoleFormFloatingActions } from './RoleFormFloatingActions';
/**
* Preferences - Roles Form content.
* Role form header.
* @returns {React.JSX}
*/
export default function RolesFormContent() {
const history = useHistory();
const { isSubmitting, values } = useFormikContext();
function RoleFormHeader() {
const roleNameFieldRef = useAutofocus();
const handleCloseClick = () => {
history.go(-1);
};
return (
<Form>
<Card>
{/* ---------- name ---------- */}
<FastField name={'role_name'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'name'} />}
label={<strong><T id={'role_name'} /></strong>}
labelInfo={<FieldRequiredHint />}
className={'form-group--name'}
intent={inputIntent({ error, touched })}
@@ -57,20 +47,28 @@ export default function RolesFormContent() {
helperText={<ErrorMessage name={'role_description'} />}
inline={true}
>
<TextArea growVertically={true} height={280} {...field} />
<TextArea
growVertically={true}
height={280}
{...field}
placeholder="Max. 500 characters"
/>
</FormGroup>
)}
</FastField>
<RolesPermissionList />
</Card>
);
}
<div className={'card__footer'}>
<Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit">
<T id={'save'} />
</Button>
<Button onClick={handleCloseClick} disabled={isSubmitting}>
<T id={'cancel'} />
</Button>
</div>
/**
* Preferences - Roles Form content.
*/
export default function RolesFormContent() {
return (
<Form>
<RoleFormHeader />
<RolesPermissionList />
<RoleFormFloatingActions />
</Form>
);
}

View File

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

View File

@@ -1,148 +1,496 @@
import React from 'react';
import { Checkbox } from '@blueprintjs/core';
import { Checkbox, Switch, Popover } from '@blueprintjs/core';
import styled from 'styled-components';
import { castArray } from 'lodash';
import { FastField } from 'formik';
import { FastField, useFormikContext } from 'formik';
import { useRolesFormContext } from './RolesFormProvider';
import { permissions, ModulePermissionsStyle } from 'common/permissionsSchema';
import { Card, If, ButtonLink, Choose } from 'components';
import {
getSerivceColumnPermission,
getServiceExtraPermissions,
} from './utils';
const RoleLabelCheckbox = ({ subject, label, description }) => (
<>
<LabelCheckbox>
{/*------------- 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>
</>
);
// Module permissions context.
const ModulePermissionsContext = React.createContext();
const ModuleServiceContext = React.createContext();
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 (
<AbilitieList>
{abilities?.map(({ key, label }) => (
<FastField name={`permissions.${subject}/${key}`} type="checkbox">
<ModulePermissionsContext.Provider value={{ module }}>
{children}
</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 }) => (
<Checkbox inline={true} label={label} {...field} />
<PermissionCheckbox inline={true} />
)}
</FastField>
))}
</AbilitieList>
</td>
</If>
);
};
}
const ExtraAbilitiesList = ({ subject, extraAbilities }) => {
return extraAbilities?.map(({ key, label }) => (
<AbilitieList>
<FastField name={`permissions.${subject}/${key}`} type="checkbox">
{({ form: { setFieldValue, values }, field }) => (
<Checkbox inline={true} label={label} {...field} />
)}
</FastField>
</AbilitieList>
));
};
export const RolesPermissionList = () => {
const { permissionsSchema } = useRolesFormContext();
/**
* Module permissions table body.
* @returns {React.JSX}
*/
function ModulePermissionsTableBody() {
const {
module: { services, columns },
} = useModulePermissionsProvider();
return (
<GroupList>
<BoxedGroupList>
{permissionsSchema.map(
({
subject,
subject_label,
description,
abilities,
extra_abilities,
}) => {
const extraAbilitiesList = Array.isArray(extra_abilities)
? extra_abilities
: [];
<tbody>
{services.map((service) => (
<ModulePermissionsServiceProvider service={service}>
<tr>
<td className="service-label">{service.label} </td>
const abilitiesList = castArray(abilities) ? abilities : [];
<ModulePermissionsServiceFullAccess />
<ModulePermissionsTableColumns columns={columns} />
<ModulePermissionExtraPermissions />
</tr>
</ModulePermissionsServiceProvider>
))}
</tbody>
);
}
return (
<React.Fragment>
<RoleList>
<RoleLabelCheckbox
subject={subject}
label={subject_label}
description={description}
/>
/**
* Module permissions table.
* @returns {React.JSX}
*/
function ModulePermissionsTable() {
return (
<ModulePermissionsTableRoot>
<ModulePermissionsTableHead />
<ModulePermissionsTableBody />
</ModulePermissionsTableRoot>
);
}
<AbilitiesList subject={subject} abilities={abilitiesList} />
<ExtraAbilitiesList
subject={subject}
extraAbilities={extraAbilitiesList}
/>
</RoleList>
</React.Fragment>
);
},
)}
</BoxedGroupList>
</GroupList>
/**
* Module vertical table cells.
* @returns {React.JSX}
*/
function ModuleVerticalTableCells() {
const { service } = useModulePermissionsServiceProvider();
return (
<td class={'permissions'}>
{service.permissions.map((permission) => (
<div>
<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`
list-style: none;
border: 1px solid #d2dce2;
border-radius: 6px;
font-size: 13px;
const PermissionCheckbox = styled(Checkbox)`
&.bp3-control.bp3-checkbox .bp3-control-indicator {
border-radius: 2px;
border-color: #555;
ul:first-child > li:last-child {
border-bottom: 0;
border-top: 0;
&,
&:before {
width: 15px;
height: 15px;
}
}
`;
const BoxedGroupList = styled.ul`
margin: 0;
list-style: none;
const ModulesPermission = styled.div``;
const ModulePermissionsRoot = styled(Card)`
padding: 0 !important;
`;
const RoleList = styled.li`
display: block;
padding: 5px 10px;
margin: 0;
line-height: 20px;
border-bottom: 1px solid #e0e0e0;
const ModulePermissionHead = styled.div`
border-bottom: 1px solid #d9d9d9;
height: 38px;
padding: 0 15px;
display: flex;
`;
const LabelCheckbox = styled.label`
> * {
display: inline-block;
}
.block {
width: 220px;
padding: 2px 0;
font-weight: 500;
const ModulePermissionTitle = styled.div`
font-weight: 500;
font-size: 16px;
line-height: 38px;
color: #878787;
`;
const ModulePermissionFullControlRoot = styled.div`
margin-left: auto;
display: flex;
.bp3-switch {
margin: auto;
}
`;
const AbilitieList = styled.ul`
list-style: none;
/* margin-left: 12px; // 10px */
margin: 0px 10px 0px;
const ModulePermissionBodyRoot = styled.div``;
> li {
display: inline-block;
margin-top: 3px;
const ModulePermissionsTableRoot = styled.table`
border-spacing: 0;
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`
display: inline-block;
margin-top: 3px;
const MorePermissionsLink = styled(ButtonLink)`
font-size: 12px;
`;
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",
"transactions": "Transactions",
"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
@import 'objects/form';
@import 'objects/switch';
@import 'objects/typography';
@import 'objects/buttons';
@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 {
overflow: auto;
.#{$ns}-tab-list {
border-bottom: 1px solid #e5e5e5;
padding-left: 15px;

View File

@@ -1,6 +1,8 @@
// Roles Form page
//---------------------------------
.preferences-page__inside-content--roles-form {
padding-bottom: 60px;
.card {
padding: 25px;
@@ -20,17 +22,21 @@
}
.bp3-form-group {
max-width: 500px;
max-width: 600px;
margin-bottom: 14px;
&.bp3-inline {
.bp3-label {
min-width: 100px;
min-width: 150px;
}
}
.bp3-form-content {
width: 100%;
}
&:last-of-type{
margin-bottom: 0;
}
}
.form-group--description {
textarea {
@@ -39,20 +45,4 @@
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 {
background: #e5eaee;
background: #eaeef6;
border-right: 1px solid #c6d0d9;
min-width: 220px;
max-width: 220px;
@@ -13,13 +13,17 @@
&__wrapper {
height: 100%;
}
.ScrollbarsCustom-Track {
&.ScrollbarsCustom-TrackY,
&.ScrollbarsCustom-TrackX {
background: rgba(0, 0, 0, 0);
}
}
.ScrollbarsCustom-Thumb {
&.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY {
background: rgba(0, 0, 0, 0);
@@ -28,6 +32,7 @@
&:hover {
.ScrollbarsCustom-Thumb {
&.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY {
background: rgba(0, 0, 0, 0.15);
@@ -68,4 +73,4 @@
}
}
}
}
}