mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Parameter table updates (#5892)
* Add some helper functions for role permission checks on frontend * Update PartParameterTable - Use new user role checks * Fix up more table action permissions * Add table for part parameter template * Add edit and delete actions to new table * Add ability to create new template from table * Fix for BomTable * Refactor RowActions - Require icon - Horizontal menu popout * Refactor row actions for existing tables * Fix BomTable * Bug fix for notifications table * Fix display of TableHoverCard * Disable PanelGroup tooltip when expanded * Fix unused variables
This commit is contained in:
parent
0597ea9216
commit
5abe0eaaad
@ -95,6 +95,7 @@ export function PanelGroup({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
label={panel.label}
|
label={panel.label}
|
||||||
key={`panel-tab-tooltip-${panel.name}`}
|
key={`panel-tab-tooltip-${panel.name}`}
|
||||||
|
disabled={expanded}
|
||||||
>
|
>
|
||||||
<Tabs.Tab
|
<Tabs.Tab
|
||||||
key={`panel-tab-${panel.name}`}
|
key={`panel-tab-${panel.name}`}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { ActionIcon, Tooltip } from '@mantine/core';
|
import { ActionIcon, Group, Tooltip } from '@mantine/core';
|
||||||
import { Menu, Text } from '@mantine/core';
|
import { Menu } from '@mantine/core';
|
||||||
import { IconDots } from '@tabler/icons-react';
|
import { IconCopy, IconDots, IconEdit, IconTrash } from '@tabler/icons-react';
|
||||||
import { ReactNode, useMemo, useState } from 'react';
|
import { ReactNode, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { notYetImplemented } from '../../functions/notifications';
|
import { notYetImplemented } from '../../functions/notifications';
|
||||||
@ -10,8 +10,8 @@ import { notYetImplemented } from '../../functions/notifications';
|
|||||||
export type RowAction = {
|
export type RowAction = {
|
||||||
title: string;
|
title: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
|
icon: ReactNode;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
tooltip?: string;
|
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ export function RowDuplicateAction({
|
|||||||
title: t`Duplicate`,
|
title: t`Duplicate`,
|
||||||
color: 'green',
|
color: 'green',
|
||||||
onClick: onClick,
|
onClick: onClick,
|
||||||
|
icon: <IconCopy />,
|
||||||
hidden: hidden
|
hidden: hidden
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -43,6 +44,7 @@ export function RowEditAction({
|
|||||||
title: t`Edit`,
|
title: t`Edit`,
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
onClick: onClick,
|
onClick: onClick,
|
||||||
|
icon: <IconEdit />,
|
||||||
hidden: hidden
|
hidden: hidden
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -59,6 +61,7 @@ export function RowDeleteAction({
|
|||||||
title: t`Delete`,
|
title: t`Delete`,
|
||||||
color: 'red',
|
color: 'red',
|
||||||
onClick: onClick,
|
onClick: onClick,
|
||||||
|
icon: <IconTrash />,
|
||||||
hidden: hidden
|
hidden: hidden
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -82,7 +85,7 @@ export function RowActions({
|
|||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
event?.stopPropagation();
|
event?.stopPropagation();
|
||||||
event?.nativeEvent?.stopImmediatePropagation();
|
event?.nativeEvent?.stopImmediatePropagation();
|
||||||
setOpened(true);
|
setOpened(!opened);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [opened, setOpened] = useState(false);
|
const [opened, setOpened] = useState(false);
|
||||||
@ -91,11 +94,45 @@ export function RowActions({
|
|||||||
return actions.filter((action) => !action.hidden);
|
return actions.filter((action) => !action.hidden);
|
||||||
}, [actions]);
|
}, [actions]);
|
||||||
|
|
||||||
|
// Render a single action icon
|
||||||
|
function RowActionIcon(action: RowAction) {
|
||||||
|
return (
|
||||||
|
<Tooltip withinPortal={true} label={action.title} key={action.title}>
|
||||||
|
<ActionIcon
|
||||||
|
color={action.color}
|
||||||
|
size={20}
|
||||||
|
onClick={(event) => {
|
||||||
|
// Prevent clicking on the action from selecting the row itself
|
||||||
|
event?.preventDefault();
|
||||||
|
event?.stopPropagation();
|
||||||
|
event?.nativeEvent?.stopImmediatePropagation();
|
||||||
|
|
||||||
|
if (action.onClick) {
|
||||||
|
action.onClick();
|
||||||
|
} else {
|
||||||
|
notYetImplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpened(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{action.icon}
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If only a single action is available, display that
|
||||||
|
if (visibleActions.length == 1) {
|
||||||
|
return <RowActionIcon {...visibleActions[0]} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
visibleActions.length > 0 && (
|
visibleActions.length > 0 && (
|
||||||
<Menu
|
<Menu
|
||||||
withinPortal={true}
|
withinPortal={true}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
position="left"
|
||||||
opened={opened}
|
opened={opened}
|
||||||
onChange={setOpened}
|
onChange={setOpened}
|
||||||
>
|
>
|
||||||
@ -112,28 +149,11 @@ export function RowActions({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
<Menu.Label>{title || t`Actions`}</Menu.Label>
|
<Group position="right" spacing="xs" p={8}>
|
||||||
{visibleActions.map((action, idx) => (
|
{visibleActions.map((action, _idx) => (
|
||||||
<Menu.Item
|
<RowActionIcon {...action} />
|
||||||
key={idx}
|
))}
|
||||||
onClick={(event) => {
|
</Group>
|
||||||
// Prevent clicking on the action from selecting the row itself
|
|
||||||
event?.preventDefault();
|
|
||||||
event?.stopPropagation();
|
|
||||||
event?.nativeEvent?.stopImmediatePropagation();
|
|
||||||
if (action.onClick) {
|
|
||||||
action.onClick();
|
|
||||||
} else {
|
|
||||||
notYetImplemented();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
title={action.tooltip || action.title}
|
|
||||||
>
|
|
||||||
<Text size="xs" color={action.color}>
|
|
||||||
{action.title}
|
|
||||||
</Text>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
)
|
||||||
|
@ -27,7 +27,7 @@ export function TableHoverCard({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverCard>
|
<HoverCard withinPortal={true}>
|
||||||
<HoverCard.Target>
|
<HoverCard.Target>
|
||||||
<Group spacing="xs" position="apart" noWrap={true}>
|
<Group spacing="xs" position="apart" noWrap={true}>
|
||||||
{value}
|
{value}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Text } from '@mantine/core';
|
import { Text } from '@mantine/core';
|
||||||
|
import {
|
||||||
|
IconArrowRight,
|
||||||
|
IconCircleCheck,
|
||||||
|
IconSwitch3
|
||||||
|
} from '@tabler/icons-react';
|
||||||
import { ReactNode, useCallback, useMemo } from 'react';
|
import { ReactNode, useCallback, useMemo } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
@ -7,7 +12,7 @@ import { bomItemFields } from '../../../forms/BomForms';
|
|||||||
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms';
|
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { useUserState } from '../../../states/UserState';
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { YesNoButton } from '../../items/YesNoButton';
|
import { YesNoButton } from '../../items/YesNoButton';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
@ -245,33 +250,34 @@ export function BomTable({
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: t`View BOM`,
|
title: t`View BOM`,
|
||||||
onClick: () => navigate(`/part/${record.part}/`)
|
onClick: () => navigate(`/part/${record.part}/`),
|
||||||
|
icon: <IconArrowRight />
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check user permissions here,
|
|
||||||
// TODO: to determine which actions are allowed
|
|
||||||
|
|
||||||
let actions: RowAction[] = [];
|
let actions: RowAction[] = [];
|
||||||
|
|
||||||
// TODO: Enable BomItem validation
|
// TODO: Enable BomItem validation
|
||||||
actions.push({
|
actions.push({
|
||||||
title: t`Validate`,
|
title: t`Validate BOM line`,
|
||||||
hidden: record.validated || !user.checkUserRole('part', 'change')
|
color: 'green',
|
||||||
|
hidden: record.validated || !user.hasChangeRole(UserRoles.part),
|
||||||
|
icon: <IconCircleCheck />
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Enable editing of substitutes
|
// TODO: Enable editing of substitutes
|
||||||
actions.push({
|
actions.push({
|
||||||
title: t`Substitutes`,
|
title: t`Edit Substitutes`,
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
hidden: !user.checkUserRole('part', 'change')
|
hidden: !user.hasChangeRole(UserRoles.part),
|
||||||
|
icon: <IconSwitch3 />
|
||||||
});
|
});
|
||||||
|
|
||||||
// Action on edit
|
// Action on edit
|
||||||
actions.push(
|
actions.push(
|
||||||
RowEditAction({
|
RowEditAction({
|
||||||
hidden: !user.checkUserRole('part', 'change'),
|
hidden: !user.hasChangeRole(UserRoles.part),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openEditApiForm({
|
openEditApiForm({
|
||||||
url: ApiPaths.bom_list,
|
url: ApiPaths.bom_list,
|
||||||
@ -288,7 +294,7 @@ export function BomTable({
|
|||||||
// Action on delete
|
// Action on delete
|
||||||
actions.push(
|
actions.push(
|
||||||
RowDeleteAction({
|
RowDeleteAction({
|
||||||
hidden: !user.checkUserRole('part', 'delete'),
|
hidden: !user.hasDeleteRole(UserRoles.part),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openDeleteApiForm({
|
openDeleteApiForm({
|
||||||
url: ApiPaths.bom_list,
|
url: ApiPaths.bom_list,
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
} from '../../../functions/forms';
|
} from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { YesNoButton } from '../../items/YesNoButton';
|
import { YesNoButton } from '../../items/YesNoButton';
|
||||||
@ -22,6 +23,8 @@ import { RowDeleteAction, RowEditAction } from '../RowActions';
|
|||||||
export function PartParameterTable({ partId }: { partId: any }) {
|
export function PartParameterTable({ partId }: { partId: any }) {
|
||||||
const { tableKey, refreshTable } = useTableRefresh('part-parameters');
|
const { tableKey, refreshTable } = useTableRefresh('part-parameters');
|
||||||
|
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
const tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -94,7 +97,6 @@ export function PartParameterTable({ partId }: { partId: any }) {
|
|||||||
}, [partId]);
|
}, [partId]);
|
||||||
|
|
||||||
// Callback for row actions
|
// Callback for row actions
|
||||||
// TODO: Adjust based on user permissions
|
|
||||||
const rowActions = useCallback(
|
const rowActions = useCallback(
|
||||||
(record: any) => {
|
(record: any) => {
|
||||||
// Actions not allowed for "variant" rows
|
// Actions not allowed for "variant" rows
|
||||||
@ -106,6 +108,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
|
|||||||
|
|
||||||
actions.push(
|
actions.push(
|
||||||
RowEditAction({
|
RowEditAction({
|
||||||
|
hidden: !user.hasChangeRole(UserRoles.part),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openEditApiForm({
|
openEditApiForm({
|
||||||
url: ApiPaths.part_parameter_list,
|
url: ApiPaths.part_parameter_list,
|
||||||
@ -127,6 +130,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
|
|||||||
|
|
||||||
actions.push(
|
actions.push(
|
||||||
RowDeleteAction({
|
RowDeleteAction({
|
||||||
|
hidden: !user.hasDeleteRole(UserRoles.part),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openDeleteApiForm({
|
openDeleteApiForm({
|
||||||
url: ApiPaths.part_parameter_list,
|
url: ApiPaths.part_parameter_list,
|
||||||
@ -144,7 +148,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
|
|||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
},
|
},
|
||||||
[partId]
|
[partId, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addParameter = useCallback(() => {
|
const addParameter = useCallback(() => {
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { Text } from '@mantine/core';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { partParameterTemplateFields } from '../../../forms/PartForms';
|
||||||
|
import {
|
||||||
|
openCreateApiForm,
|
||||||
|
openDeleteApiForm,
|
||||||
|
openEditApiForm
|
||||||
|
} from '../../../functions/forms';
|
||||||
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
|
import { TableColumn } from '../Column';
|
||||||
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
import { RowDeleteAction, RowEditAction } from '../RowActions';
|
||||||
|
|
||||||
|
export function PartParameterTemplateTable() {
|
||||||
|
const { tableKey, refreshTable } = useTableRefresh(
|
||||||
|
'part-parameter-templates'
|
||||||
|
);
|
||||||
|
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
accessor: 'name',
|
||||||
|
title: t`Name`,
|
||||||
|
sortable: true,
|
||||||
|
switchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'units',
|
||||||
|
title: t`Units`,
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'description',
|
||||||
|
title: t`Description`,
|
||||||
|
sortbale: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'checkbox',
|
||||||
|
title: t`Checkbox`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'choices',
|
||||||
|
title: t`Choices`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Callback for row actions
|
||||||
|
const rowActions = useCallback(
|
||||||
|
(record: any) => {
|
||||||
|
return [
|
||||||
|
RowEditAction({
|
||||||
|
hidden: !user.hasChangeRole(UserRoles.part),
|
||||||
|
onClick: () => {
|
||||||
|
openEditApiForm({
|
||||||
|
url: ApiPaths.part_parameter_template_list,
|
||||||
|
pk: record.pk,
|
||||||
|
title: t`Edit Parameter Template`,
|
||||||
|
fields: partParameterTemplateFields(),
|
||||||
|
successMessage: t`Parameter template updated`,
|
||||||
|
onFormSuccess: refreshTable
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
RowDeleteAction({
|
||||||
|
hidden: !user.hasDeleteRole(UserRoles.part),
|
||||||
|
onClick: () => {
|
||||||
|
openDeleteApiForm({
|
||||||
|
url: ApiPaths.part_parameter_template_list,
|
||||||
|
pk: record.pk,
|
||||||
|
title: t`Delete Parameter Template`,
|
||||||
|
successMessage: t`Parameter template deleted`,
|
||||||
|
onFormSuccess: refreshTable,
|
||||||
|
preFormContent: <Text>{t`Remove parameter template`}</Text>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
|
const addParameterTemplate = useCallback(() => {
|
||||||
|
openCreateApiForm({
|
||||||
|
url: ApiPaths.part_parameter_template_list,
|
||||||
|
title: t`Create Parameter Template`,
|
||||||
|
fields: partParameterTemplateFields(),
|
||||||
|
successMessage: t`Parameter template created`,
|
||||||
|
onFormSuccess: refreshTable
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const tableActions = useMemo(() => {
|
||||||
|
return [
|
||||||
|
<AddItemButton
|
||||||
|
tooltip={t`Add parameter template`}
|
||||||
|
onClick={addParameterTemplate}
|
||||||
|
disabled={!user.hasAddRole(UserRoles.part)}
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InvenTreeTable
|
||||||
|
url={apiUrl(ApiPaths.part_parameter_template_list)}
|
||||||
|
tableKey={tableKey}
|
||||||
|
columns={tableColumns}
|
||||||
|
props={{
|
||||||
|
rowActions: rowActions,
|
||||||
|
customActionGroups: tableActions
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -7,6 +7,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { openCreateApiForm, openDeleteApiForm } from '../../../functions/forms';
|
import { openCreateApiForm, openDeleteApiForm } from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
@ -20,6 +21,8 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
|
|||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
// Construct table columns for this table
|
// Construct table columns for this table
|
||||||
const tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
function getPart(record: any) {
|
function getPart(record: any) {
|
||||||
@ -96,24 +99,28 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
|
|||||||
|
|
||||||
// Generate row actions
|
// Generate row actions
|
||||||
// TODO: Hide if user does not have permission to edit parts
|
// TODO: Hide if user does not have permission to edit parts
|
||||||
const rowActions = useCallback((record: any) => {
|
const rowActions = useCallback(
|
||||||
return [
|
(record: any) => {
|
||||||
RowDeleteAction({
|
return [
|
||||||
onClick: () => {
|
RowDeleteAction({
|
||||||
openDeleteApiForm({
|
hidden: !user.hasDeleteRole(UserRoles.part),
|
||||||
url: ApiPaths.related_part_list,
|
onClick: () => {
|
||||||
pk: record.pk,
|
openDeleteApiForm({
|
||||||
title: t`Delete Related Part`,
|
url: ApiPaths.related_part_list,
|
||||||
successMessage: t`Related part deleted`,
|
pk: record.pk,
|
||||||
preFormContent: (
|
title: t`Delete Related Part`,
|
||||||
<Text>{t`Are you sure you want to remove this relationship?`}</Text>
|
successMessage: t`Related part deleted`,
|
||||||
),
|
preFormContent: (
|
||||||
onFormSuccess: refreshTable
|
<Text>{t`Are you sure you want to remove this relationship?`}</Text>
|
||||||
});
|
),
|
||||||
}
|
onFormSuccess: refreshTable
|
||||||
})
|
});
|
||||||
];
|
}
|
||||||
}, []);
|
})
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { notYetImplemented } from '../../../functions/notifications';
|
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
@ -102,16 +101,13 @@ export function PluginListTable({ props }: { props: InvenTreeTableProps }) {
|
|||||||
actions.push({
|
actions.push({
|
||||||
title: t`Deactivate`,
|
title: t`Deactivate`,
|
||||||
color: 'red',
|
color: 'red',
|
||||||
onClick: () => {
|
icon: <IconCircleX />
|
||||||
notYetImplemented();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
actions.push({
|
actions.push({
|
||||||
title: t`Activate`,
|
title: t`Activate`,
|
||||||
onClick: () => {
|
color: 'green',
|
||||||
notYetImplemented();
|
icon: <IconCircleCheck />
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { purchaseOrderLineItemFields } from '../../../forms/PurchaseOrderForms';
|
|||||||
import { openCreateApiForm, openEditApiForm } from '../../../functions/forms';
|
import { openCreateApiForm, openEditApiForm } from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { useUserState } from '../../../states/UserState';
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { ActionButton } from '../../buttons/ActionButton';
|
import { ActionButton } from '../../buttons/ActionButton';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
@ -45,18 +45,17 @@ export function PurchaseOrderLineItemTable({
|
|||||||
|
|
||||||
const rowActions = useCallback(
|
const rowActions = useCallback(
|
||||||
(record: any) => {
|
(record: any) => {
|
||||||
// TODO: Hide certain actions if user does not have required permissions
|
|
||||||
|
|
||||||
let received = (record?.received ?? 0) >= (record?.quantity ?? 0);
|
let received = (record?.received ?? 0) >= (record?.quantity ?? 0);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
hidden: received,
|
hidden: received,
|
||||||
title: t`Receive`,
|
title: t`Receive line item`,
|
||||||
tooltip: t`Receive line item`,
|
icon: <IconSquareArrowRight />,
|
||||||
color: 'green'
|
color: 'green'
|
||||||
},
|
},
|
||||||
RowEditAction({
|
RowEditAction({
|
||||||
|
hidden: !user.hasAddRole(UserRoles.purchase_order),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
let supplier = record?.supplier_part_detail?.supplier;
|
let supplier = record?.supplier_part_detail?.supplier;
|
||||||
|
|
||||||
@ -78,8 +77,12 @@ export function PurchaseOrderLineItemTable({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
RowDuplicateAction({}),
|
RowDuplicateAction({
|
||||||
RowDeleteAction({})
|
hidden: !user.hasAddRole(UserRoles.purchase_order)
|
||||||
|
}),
|
||||||
|
RowDeleteAction({
|
||||||
|
hidden: !user.hasDeleteRole(UserRoles.purchase_order)
|
||||||
|
})
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[orderId, user]
|
[orderId, user]
|
||||||
@ -228,7 +231,7 @@ export function PurchaseOrderLineItemTable({
|
|||||||
<AddItemButton
|
<AddItemButton
|
||||||
tooltip={t`Add line item`}
|
tooltip={t`Add line item`}
|
||||||
onClick={addLine}
|
onClick={addLine}
|
||||||
hidden={!user?.checkUserRole('purchaseorder', 'add')}
|
hidden={!user?.hasAddRole(UserRoles.purchase_order)}
|
||||||
/>,
|
/>,
|
||||||
<ActionButton text={t`Receive items`} icon={<IconSquareArrowRight />} />
|
<ActionButton text={t`Receive items`} icon={<IconSquareArrowRight />} />
|
||||||
];
|
];
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
} from '../../../functions/forms';
|
} from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { useUserState } from '../../../states/UserState';
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
@ -180,9 +180,9 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
|
|||||||
// Row action callback
|
// Row action callback
|
||||||
const rowActions = useCallback(
|
const rowActions = useCallback(
|
||||||
(record: any) => {
|
(record: any) => {
|
||||||
// TODO: Adjust actions based on user permissions
|
|
||||||
return [
|
return [
|
||||||
RowEditAction({
|
RowEditAction({
|
||||||
|
hidden: !user.hasChangeRole(UserRoles.purchase_order),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
record.pk &&
|
record.pk &&
|
||||||
openEditApiForm({
|
openEditApiForm({
|
||||||
@ -196,6 +196,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
RowDeleteAction({
|
RowDeleteAction({
|
||||||
|
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
record.pk &&
|
record.pk &&
|
||||||
openDeleteApiForm({
|
openDeleteApiForm({
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
} from '../../../functions/forms';
|
} from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
@ -20,6 +21,8 @@ import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
|||||||
export function CustomUnitsTable() {
|
export function CustomUnitsTable() {
|
||||||
const { tableKey, refreshTable } = useTableRefresh('custom-units');
|
const { tableKey, refreshTable } = useTableRefresh('custom-units');
|
||||||
|
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
const columns: TableColumn[] = useMemo(() => {
|
const columns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -43,40 +46,45 @@ export function CustomUnitsTable() {
|
|||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const rowActions = useCallback((record: any): RowAction[] => {
|
const rowActions = useCallback(
|
||||||
return [
|
(record: any): RowAction[] => {
|
||||||
RowEditAction({
|
return [
|
||||||
onClick: () => {
|
RowEditAction({
|
||||||
openEditApiForm({
|
hidden: !user.hasChangeRole(UserRoles.admin),
|
||||||
url: ApiPaths.custom_unit_list,
|
onClick: () => {
|
||||||
pk: record.pk,
|
openEditApiForm({
|
||||||
title: t`Edit custom unit`,
|
url: ApiPaths.custom_unit_list,
|
||||||
fields: {
|
pk: record.pk,
|
||||||
name: {},
|
title: t`Edit custom unit`,
|
||||||
definition: {},
|
fields: {
|
||||||
symbol: {}
|
name: {},
|
||||||
},
|
definition: {},
|
||||||
onFormSuccess: refreshTable,
|
symbol: {}
|
||||||
successMessage: t`Custom unit updated`
|
},
|
||||||
});
|
onFormSuccess: refreshTable,
|
||||||
}
|
successMessage: t`Custom unit updated`
|
||||||
}),
|
});
|
||||||
RowDeleteAction({
|
}
|
||||||
onClick: () => {
|
}),
|
||||||
openDeleteApiForm({
|
RowDeleteAction({
|
||||||
url: ApiPaths.custom_unit_list,
|
hidden: !user.hasDeleteRole(UserRoles.admin),
|
||||||
pk: record.pk,
|
onClick: () => {
|
||||||
title: t`Delete custom unit`,
|
openDeleteApiForm({
|
||||||
successMessage: t`Custom unit deleted`,
|
url: ApiPaths.custom_unit_list,
|
||||||
onFormSuccess: refreshTable,
|
pk: record.pk,
|
||||||
preFormContent: (
|
title: t`Delete custom unit`,
|
||||||
<Text>{t`Are you sure you want to remove this custom unit?`}</Text>
|
successMessage: t`Custom unit deleted`,
|
||||||
)
|
onFormSuccess: refreshTable,
|
||||||
});
|
preFormContent: (
|
||||||
}
|
<Text>{t`Are you sure you want to remove this custom unit?`}</Text>
|
||||||
})
|
)
|
||||||
];
|
});
|
||||||
}, []);
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
const addCustomUnit = useCallback(() => {
|
const addCustomUnit = useCallback(() => {
|
||||||
openCreateApiForm({
|
openCreateApiForm({
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
} from '../../../functions/forms';
|
} from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
|
import { UserRoles, useUserState } from '../../../states/UserState';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { DescriptionColumn } from '../ColumnRenderers';
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
@ -21,6 +22,8 @@ import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
|||||||
export function ProjectCodeTable() {
|
export function ProjectCodeTable() {
|
||||||
const { tableKey, refreshTable } = useTableRefresh('project-code');
|
const { tableKey, refreshTable } = useTableRefresh('project-code');
|
||||||
|
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
const columns: TableColumn[] = useMemo(() => {
|
const columns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -32,39 +35,44 @@ export function ProjectCodeTable() {
|
|||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const rowActions = useCallback((record: any): RowAction[] => {
|
const rowActions = useCallback(
|
||||||
return [
|
(record: any): RowAction[] => {
|
||||||
RowEditAction({
|
return [
|
||||||
onClick: () => {
|
RowEditAction({
|
||||||
openEditApiForm({
|
hidden: !user.hasChangeRole(UserRoles.admin),
|
||||||
url: ApiPaths.project_code_list,
|
onClick: () => {
|
||||||
pk: record.pk,
|
openEditApiForm({
|
||||||
title: t`Edit project code`,
|
url: ApiPaths.project_code_list,
|
||||||
fields: {
|
pk: record.pk,
|
||||||
code: {},
|
title: t`Edit project code`,
|
||||||
description: {}
|
fields: {
|
||||||
},
|
code: {},
|
||||||
onFormSuccess: refreshTable,
|
description: {}
|
||||||
successMessage: t`Project code updated`
|
},
|
||||||
});
|
onFormSuccess: refreshTable,
|
||||||
}
|
successMessage: t`Project code updated`
|
||||||
}),
|
});
|
||||||
RowDeleteAction({
|
}
|
||||||
onClick: () => {
|
}),
|
||||||
openDeleteApiForm({
|
RowDeleteAction({
|
||||||
url: ApiPaths.project_code_list,
|
hidden: !user.hasDeleteRole(UserRoles.admin),
|
||||||
pk: record.pk,
|
onClick: () => {
|
||||||
title: t`Delete project code`,
|
openDeleteApiForm({
|
||||||
successMessage: t`Project code deleted`,
|
url: ApiPaths.project_code_list,
|
||||||
onFormSuccess: refreshTable,
|
pk: record.pk,
|
||||||
preFormContent: (
|
title: t`Delete project code`,
|
||||||
<Text>{t`Are you sure you want to remove this project code?`}</Text>
|
successMessage: t`Project code deleted`,
|
||||||
)
|
onFormSuccess: refreshTable,
|
||||||
});
|
preFormContent: (
|
||||||
}
|
<Text>{t`Are you sure you want to remove this project code?`}</Text>
|
||||||
})
|
)
|
||||||
];
|
});
|
||||||
}, []);
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
const addProjectCode = useCallback(() => {
|
const addProjectCode = useCallback(() => {
|
||||||
openCreateApiForm({
|
openCreateApiForm({
|
||||||
|
@ -121,3 +121,13 @@ export function partCategoryFields({}: {}): ApiFormFieldSet {
|
|||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function partParameterTemplateFields(): ApiFormFieldSet {
|
||||||
|
return {
|
||||||
|
name: {},
|
||||||
|
description: {},
|
||||||
|
units: {},
|
||||||
|
choices: {},
|
||||||
|
checkbox: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@ import { StylishText } from '../../../components/items/StylishText';
|
|||||||
import { PanelGroup, PanelType } from '../../../components/nav/PanelGroup';
|
import { PanelGroup, PanelType } from '../../../components/nav/PanelGroup';
|
||||||
import { SettingsHeader } from '../../../components/nav/SettingsHeader';
|
import { SettingsHeader } from '../../../components/nav/SettingsHeader';
|
||||||
import { GlobalSettingList } from '../../../components/settings/SettingList';
|
import { GlobalSettingList } from '../../../components/settings/SettingList';
|
||||||
|
import { PartParameterTemplateTable } from '../../../components/tables/part/PartParameterTemplateTable';
|
||||||
import { CurrencyTable } from '../../../components/tables/settings/CurrencyTable';
|
import { CurrencyTable } from '../../../components/tables/settings/CurrencyTable';
|
||||||
import { CustomUnitsTable } from '../../../components/tables/settings/CustomUnitsTable';
|
import { CustomUnitsTable } from '../../../components/tables/settings/CustomUnitsTable';
|
||||||
import { ProjectCodeTable } from '../../../components/tables/settings/ProjectCodeTable';
|
import { ProjectCodeTable } from '../../../components/tables/settings/ProjectCodeTable';
|
||||||
@ -220,7 +221,8 @@ export default function SystemSettings() {
|
|||||||
{
|
{
|
||||||
name: 'parameters',
|
name: 'parameters',
|
||||||
label: t`Part Parameters`,
|
label: t`Part Parameters`,
|
||||||
icon: <IconList />
|
icon: <IconList />,
|
||||||
|
content: <PartParameterTemplateTable />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'stock',
|
name: 'stock',
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Stack } from '@mantine/core';
|
import { Stack } from '@mantine/core';
|
||||||
import { IconBellCheck, IconBellExclamation } from '@tabler/icons-react';
|
import {
|
||||||
|
IconBellCheck,
|
||||||
|
IconBellExclamation,
|
||||||
|
IconCircleCheck,
|
||||||
|
IconCircleX,
|
||||||
|
IconTrash
|
||||||
|
} from '@tabler/icons-react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
@ -27,6 +33,8 @@ export default function NotificationsPage() {
|
|||||||
actions={(record) => [
|
actions={(record) => [
|
||||||
{
|
{
|
||||||
title: t`Mark as read`,
|
title: t`Mark as read`,
|
||||||
|
color: 'green',
|
||||||
|
icon: <IconCircleCheck />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
let url = apiUrl(ApiPaths.notifications_list, record.pk);
|
let url = apiUrl(ApiPaths.notifications_list, record.pk);
|
||||||
api
|
api
|
||||||
@ -53,6 +61,7 @@ export default function NotificationsPage() {
|
|||||||
actions={(record) => [
|
actions={(record) => [
|
||||||
{
|
{
|
||||||
title: t`Mark as unread`,
|
title: t`Mark as unread`,
|
||||||
|
icon: <IconCircleX />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
let url = apiUrl(ApiPaths.notifications_list, record.pk);
|
let url = apiUrl(ApiPaths.notifications_list, record.pk);
|
||||||
|
|
||||||
@ -68,9 +77,10 @@ export default function NotificationsPage() {
|
|||||||
{
|
{
|
||||||
title: t`Delete`,
|
title: t`Delete`,
|
||||||
color: 'red',
|
color: 'red',
|
||||||
|
icon: <IconTrash />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
api
|
api
|
||||||
.delete(`/notifications/${record.pk}/`)
|
.delete(apiUrl(ApiPaths.notifications_list, record.pk))
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
historyRefresh.refreshTable();
|
historyRefresh.refreshTable();
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@ import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
|||||||
import { editCompany } from '../../forms/CompanyForms';
|
import { editCompany } from '../../forms/CompanyForms';
|
||||||
import { useInstance } from '../../hooks/UseInstance';
|
import { useInstance } from '../../hooks/UseInstance';
|
||||||
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { UserRoles, useUserState } from '../../states/UserState';
|
||||||
|
|
||||||
export type CompanyDetailProps = {
|
export type CompanyDetailProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -161,10 +161,6 @@ export default function CompanyDetail(props: CompanyDetailProps) {
|
|||||||
}, [id, company]);
|
}, [id, company]);
|
||||||
|
|
||||||
const companyActions = useMemo(() => {
|
const companyActions = useMemo(() => {
|
||||||
// TODO: Finer fidelity on these permissions, perhaps?
|
|
||||||
let canEdit = user.checkUserRole('purchase_order', 'change');
|
|
||||||
let canDelete = user.checkUserRole('purchase_order', 'delete');
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
<ActionDropdown
|
<ActionDropdown
|
||||||
key="company"
|
key="company"
|
||||||
@ -172,7 +168,7 @@ export default function CompanyDetail(props: CompanyDetailProps) {
|
|||||||
icon={<IconDots />}
|
icon={<IconDots />}
|
||||||
actions={[
|
actions={[
|
||||||
EditItemAction({
|
EditItemAction({
|
||||||
disabled: !canEdit,
|
disabled: !user.hasChangeRole(UserRoles.purchase_order),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
if (company?.pk) {
|
if (company?.pk) {
|
||||||
editCompany({
|
editCompany({
|
||||||
@ -183,7 +179,7 @@ export default function CompanyDetail(props: CompanyDetailProps) {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
DeleteItemAction({
|
DeleteItemAction({
|
||||||
disabled: !canDelete
|
disabled: !user.hasDeleteRole(UserRoles.purchase_order)
|
||||||
})
|
})
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -5,12 +5,42 @@ import { doClassicLogout } from '../functions/auth';
|
|||||||
import { ApiPaths, apiUrl } from './ApiState';
|
import { ApiPaths, apiUrl } from './ApiState';
|
||||||
import { UserProps } from './states';
|
import { UserProps } from './states';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumeration of available user role groups
|
||||||
|
*/
|
||||||
|
export enum UserRoles {
|
||||||
|
admin = 'admin',
|
||||||
|
build = 'build',
|
||||||
|
part = 'part',
|
||||||
|
part_category = 'part_category',
|
||||||
|
purchase_order = 'purchase_order',
|
||||||
|
return_order = 'return_order',
|
||||||
|
sales_order = 'sales_order',
|
||||||
|
stock = 'stock',
|
||||||
|
stock_location = 'stocklocation',
|
||||||
|
stocktake = 'stocktake'
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumeration of available user permissions within each role group
|
||||||
|
*/
|
||||||
|
export enum UserPermissions {
|
||||||
|
view = 'view',
|
||||||
|
add = 'add',
|
||||||
|
change = 'change',
|
||||||
|
delete = 'delete'
|
||||||
|
}
|
||||||
|
|
||||||
interface UserStateProps {
|
interface UserStateProps {
|
||||||
user: UserProps | undefined;
|
user: UserProps | undefined;
|
||||||
username: () => string;
|
username: () => string;
|
||||||
setUser: (newUser: UserProps) => void;
|
setUser: (newUser: UserProps) => void;
|
||||||
fetchUserState: () => void;
|
fetchUserState: () => void;
|
||||||
checkUserRole: (role: string, permission: string) => boolean;
|
checkUserRole: (role: UserRoles, permission: UserPermissions) => boolean;
|
||||||
|
hasDeleteRole: (role: UserRoles) => boolean;
|
||||||
|
hasChangeRole: (role: UserRoles) => boolean;
|
||||||
|
hasAddRole: (role: UserRoles) => boolean;
|
||||||
|
hasViewRole: (role: UserRoles) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +95,7 @@ export const useUserState = create<UserStateProps>((set, get) => ({
|
|||||||
console.error('Error fetching user roles:', error);
|
console.error('Error fetching user roles:', error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
checkUserRole: (role: string, permission: string) => {
|
checkUserRole: (role: UserRoles, permission: UserPermissions) => {
|
||||||
// Check if the user has the specified permission for the specified role
|
// Check if the user has the specified permission for the specified role
|
||||||
const user: UserProps = get().user as UserProps;
|
const user: UserProps = get().user as UserProps;
|
||||||
|
|
||||||
@ -74,5 +104,17 @@ export const useUserState = create<UserStateProps>((set, get) => ({
|
|||||||
if (user.roles[role] === undefined) return false;
|
if (user.roles[role] === undefined) return false;
|
||||||
|
|
||||||
return user.roles[role].includes(permission);
|
return user.roles[role].includes(permission);
|
||||||
|
},
|
||||||
|
hasDeleteRole: (role: UserRoles) => {
|
||||||
|
return get().checkUserRole(role, UserPermissions.delete);
|
||||||
|
},
|
||||||
|
hasChangeRole: (role: UserRoles) => {
|
||||||
|
return get().checkUserRole(role, UserPermissions.change);
|
||||||
|
},
|
||||||
|
hasAddRole: (role: UserRoles) => {
|
||||||
|
return get().checkUserRole(role, UserPermissions.add);
|
||||||
|
},
|
||||||
|
hasViewRole: (role: UserRoles) => {
|
||||||
|
return get().checkUserRole(role, UserPermissions.view);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
Loading…
Reference in New Issue
Block a user