mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	fix various sonarlint warnings (#8479)
Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
		@@ -30,14 +30,14 @@ export default function DashboardMenu({
 | 
				
			|||||||
  onStartEdit,
 | 
					  onStartEdit,
 | 
				
			||||||
  onStartRemove,
 | 
					  onStartRemove,
 | 
				
			||||||
  onAcceptLayout
 | 
					  onAcceptLayout
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  editing: boolean;
 | 
					  editing: boolean;
 | 
				
			||||||
  removing: boolean;
 | 
					  removing: boolean;
 | 
				
			||||||
  onAddWidget: () => void;
 | 
					  onAddWidget: () => void;
 | 
				
			||||||
  onStartEdit: () => void;
 | 
					  onStartEdit: () => void;
 | 
				
			||||||
  onStartRemove: () => void;
 | 
					  onStartRemove: () => void;
 | 
				
			||||||
  onAcceptLayout: () => void;
 | 
					  onAcceptLayout: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const instanceName = useInstanceName();
 | 
					  const instanceName = useInstanceName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,12 +29,12 @@ export default function DashboardWidget({
 | 
				
			|||||||
  editing,
 | 
					  editing,
 | 
				
			||||||
  removing,
 | 
					  removing,
 | 
				
			||||||
  onRemove
 | 
					  onRemove
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  item: DashboardWidgetProps;
 | 
					  item: DashboardWidgetProps;
 | 
				
			||||||
  editing: boolean;
 | 
					  editing: boolean;
 | 
				
			||||||
  removing: boolean;
 | 
					  removing: boolean;
 | 
				
			||||||
  onRemove: () => void;
 | 
					  onRemove: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  // TODO: Implement visibility check
 | 
					  // TODO: Implement visibility check
 | 
				
			||||||
  //     if (!props?.visible?.() == false) {
 | 
					  //     if (!props?.visible?.() == false) {
 | 
				
			||||||
  //     return null;
 | 
					  //     return null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,12 +26,12 @@ export default function DashboardWidgetDrawer({
 | 
				
			|||||||
  onClose,
 | 
					  onClose,
 | 
				
			||||||
  onAddWidget,
 | 
					  onAddWidget,
 | 
				
			||||||
  currentWidgets
 | 
					  currentWidgets
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  opened: boolean;
 | 
					  opened: boolean;
 | 
				
			||||||
  onClose: () => void;
 | 
					  onClose: () => void;
 | 
				
			||||||
  onAddWidget: (widget: string) => void;
 | 
					  onAddWidget: (widget: string) => void;
 | 
				
			||||||
  currentWidgets: string[];
 | 
					  currentWidgets: string[];
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  // Load available widgets
 | 
					  // Load available widgets
 | 
				
			||||||
  const availableWidgets = useDashboardItems();
 | 
					  const availableWidgets = useDashboardItems();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ import { StylishText } from '../../items/StylishText';
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Render a link to an external news item
 | 
					 * Render a link to an external news item
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function NewsLink({ item }: { item: any }) {
 | 
					function NewsLink({ item }: Readonly<{ item: any }>) {
 | 
				
			||||||
  let link: string = item.link;
 | 
					  let link: string = item.link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (link?.startsWith('/')) {
 | 
					  if (link?.startsWith('/')) {
 | 
				
			||||||
@@ -45,10 +45,10 @@ function NewsLink({ item }: { item: any }) {
 | 
				
			|||||||
function NewsItem({
 | 
					function NewsItem({
 | 
				
			||||||
  item,
 | 
					  item,
 | 
				
			||||||
  onMarkRead
 | 
					  onMarkRead
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  item: any;
 | 
					  item: any;
 | 
				
			||||||
  onMarkRead: (id: number) => void;
 | 
					  onMarkRead: (id: number) => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const date: string = item.published?.split(' ')[0] ?? '';
 | 
					  const date: string = item.published?.split(' ')[0] ?? '';
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Table.Tr>
 | 
					    <Table.Tr>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,12 +25,12 @@ function QueryCountWidget({
 | 
				
			|||||||
  title,
 | 
					  title,
 | 
				
			||||||
  icon,
 | 
					  icon,
 | 
				
			||||||
  params
 | 
					  params
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  modelType: ModelType;
 | 
					  modelType: ModelType;
 | 
				
			||||||
  title: string;
 | 
					  title: string;
 | 
				
			||||||
  icon?: InvenTreeIconType;
 | 
					  icon?: InvenTreeIconType;
 | 
				
			||||||
  params: any;
 | 
					  params: any;
 | 
				
			||||||
}): ReactNode {
 | 
					}>): ReactNode {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,10 @@ import { LanguageToggle } from '../items/LanguageToggle';
 | 
				
			|||||||
export function AuthFormOptions({
 | 
					export function AuthFormOptions({
 | 
				
			||||||
  hostname,
 | 
					  hostname,
 | 
				
			||||||
  toggleHostEdit
 | 
					  toggleHostEdit
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  hostname: string;
 | 
					  hostname: string;
 | 
				
			||||||
  toggleHostEdit: () => void;
 | 
					  toggleHostEdit: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const [server] = useServerApiState((state) => [state.server]);
 | 
					  const [server] = useServerApiState((state) => [state.server]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ function TableFieldRow({
 | 
				
			|||||||
  control,
 | 
					  control,
 | 
				
			||||||
  changeFn,
 | 
					  changeFn,
 | 
				
			||||||
  removeFn
 | 
					  removeFn
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  item: any;
 | 
					  item: any;
 | 
				
			||||||
  idx: number;
 | 
					  idx: number;
 | 
				
			||||||
  errors: any;
 | 
					  errors: any;
 | 
				
			||||||
@@ -34,7 +34,7 @@ function TableFieldRow({
 | 
				
			|||||||
  control: UseControllerReturn<FieldValues, any>;
 | 
					  control: UseControllerReturn<FieldValues, any>;
 | 
				
			||||||
  changeFn: (idx: number, key: string, value: any) => void;
 | 
					  changeFn: (idx: number, key: string, value: any) => void;
 | 
				
			||||||
  removeFn: (idx: number) => void;
 | 
					  removeFn: (idx: number) => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  // Table fields require render function
 | 
					  // Table fields require render function
 | 
				
			||||||
  if (!definition.modelRenderer) {
 | 
					  if (!definition.modelRenderer) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
@@ -62,11 +62,11 @@ export function TableFieldErrorWrapper({
 | 
				
			|||||||
  props,
 | 
					  props,
 | 
				
			||||||
  errorKey,
 | 
					  errorKey,
 | 
				
			||||||
  children
 | 
					  children
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  props: TableFieldRowProps;
 | 
					  props: TableFieldRowProps;
 | 
				
			||||||
  errorKey: string;
 | 
					  errorKey: string;
 | 
				
			||||||
  children: ReactNode;
 | 
					  children: ReactNode;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const msg = props?.rowErrors?.[errorKey];
 | 
					  const msg = props?.rowErrors?.[errorKey];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import * as classes from './GettingStartedCarousel.css';
 | 
				
			|||||||
import type { MenuLinkItem } from './MenuLinks';
 | 
					import type { MenuLinkItem } from './MenuLinks';
 | 
				
			||||||
import { StylishText } from './StylishText';
 | 
					import { StylishText } from './StylishText';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function StartedCard({ title, description, link }: MenuLinkItem) {
 | 
					function StartedCard({ title, description, link }: Readonly<MenuLinkItem>) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Paper shadow='md' p='xl' radius='md' className={classes.card}>
 | 
					    <Paper shadow='md' p='xl' radius='md' className={classes.card}>
 | 
				
			||||||
      <div>
 | 
					      <div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ import { api } from '../../App';
 | 
				
			|||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
 | 
					import { ApiEndpoints } from '../../enums/ApiEndpoints';
 | 
				
			||||||
import { apiUrl } from '../../states/ApiState';
 | 
					import { apiUrl } from '../../states/ApiState';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function LicenceView(entries: any[]) {
 | 
					export function LicenceView(entries: Readonly<any[]>) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Stack gap='xs'>
 | 
					    <Stack gap='xs'>
 | 
				
			||||||
      <Divider />
 | 
					      <Divider />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ export function NavigationDrawer({
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function DrawerContent({ closeFunc }: { closeFunc?: () => void }) {
 | 
					function DrawerContent({ closeFunc }: Readonly<{ closeFunc?: () => void }>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const globalSettings = useGlobalSettingsState();
 | 
					  const globalSettings = useGlobalSettingsState();
 | 
				
			||||||
@@ -186,13 +186,11 @@ function DrawerContent({ closeFunc }: { closeFunc?: () => void }) {
 | 
				
			|||||||
          />
 | 
					          />
 | 
				
			||||||
          <Space h='md' />
 | 
					          <Space h='md' />
 | 
				
			||||||
          {plugins.length > 0 ? (
 | 
					          {plugins.length > 0 ? (
 | 
				
			||||||
            <>
 | 
					            <MenuLinks
 | 
				
			||||||
              <MenuLinks
 | 
					              title={t`Plugins`}
 | 
				
			||||||
                title={t`Plugins`}
 | 
					              links={plugins}
 | 
				
			||||||
                links={plugins}
 | 
					              beforeClick={closeFunc}
 | 
				
			||||||
                beforeClick={closeFunc}
 | 
					            />
 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </>
 | 
					 | 
				
			||||||
          ) : (
 | 
					          ) : (
 | 
				
			||||||
            <></>
 | 
					            <></>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,10 +36,10 @@ import { ModelInformationDict } from '../render/ModelType';
 | 
				
			|||||||
function NotificationEntry({
 | 
					function NotificationEntry({
 | 
				
			||||||
  notification,
 | 
					  notification,
 | 
				
			||||||
  onRead
 | 
					  onRead
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  notification: any;
 | 
					  notification: any;
 | 
				
			||||||
  onRead: () => void;
 | 
					  onRead: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let link = notification.target?.link;
 | 
					  let link = notification.target?.link;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,10 @@ import { useGlobalSettingsState } from '../../states/SettingsState';
 | 
				
			|||||||
export default function PageTitle({
 | 
					export default function PageTitle({
 | 
				
			||||||
  title,
 | 
					  title,
 | 
				
			||||||
  subtitle
 | 
					  subtitle
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  title?: string;
 | 
					  title?: string;
 | 
				
			||||||
  subtitle?: string;
 | 
					  subtitle?: string;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const globalSettings = useGlobalSettingsState();
 | 
					  const globalSettings = useGlobalSettingsState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const pageTitle = useMemo(() => {
 | 
					  const pageTitle = useMemo(() => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,10 +12,10 @@ import type { PluginInterface } from './PluginInterface';
 | 
				
			|||||||
export default function LocateItemButton({
 | 
					export default function LocateItemButton({
 | 
				
			||||||
  stockId,
 | 
					  stockId,
 | 
				
			||||||
  locationId
 | 
					  locationId
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  stockId?: number;
 | 
					  stockId?: number;
 | 
				
			||||||
  locationId?: number;
 | 
					  locationId?: number;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const locatePlugins = usePluginsWithMixin('locate');
 | 
					  const locatePlugins = usePluginsWithMixin('locate');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [selectedPlugin, setSelectedPlugin] = useState<string | undefined>(
 | 
					  const [selectedPlugin, setSelectedPlugin] = useState<string | undefined>(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,10 @@ import PluginSettingsPanel from './PluginSettingsPanel';
 | 
				
			|||||||
export default function PluginDrawer({
 | 
					export default function PluginDrawer({
 | 
				
			||||||
  pluginKey,
 | 
					  pluginKey,
 | 
				
			||||||
  pluginInstance
 | 
					  pluginInstance
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  pluginKey?: string;
 | 
					  pluginKey?: string;
 | 
				
			||||||
  pluginInstance: PluginInterface;
 | 
					  pluginInstance: PluginInterface;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const { id } = useParams();
 | 
					  const { id } = useParams();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const pluginPrimaryKey: string = useMemo(() => {
 | 
					  const pluginPrimaryKey: string = useMemo(() => {
 | 
				
			||||||
@@ -53,106 +53,104 @@ export default function PluginDrawer({
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <Accordion defaultValue={['plugin-details', 'plugin-settings']} multiple>
 | 
				
			||||||
      <Accordion defaultValue={['plugin-details', 'plugin-settings']} multiple>
 | 
					      <Accordion.Item value='plugin-details'>
 | 
				
			||||||
        <Accordion.Item value='plugin-details'>
 | 
					        <Accordion.Control>
 | 
				
			||||||
 | 
					          <StylishText size='lg'>{t`Plugin Information`}</StylishText>
 | 
				
			||||||
 | 
					        </Accordion.Control>
 | 
				
			||||||
 | 
					        <Accordion.Panel>
 | 
				
			||||||
 | 
					          <Stack gap='xs'>
 | 
				
			||||||
 | 
					            <Card withBorder>
 | 
				
			||||||
 | 
					              <Stack gap='md'>
 | 
				
			||||||
 | 
					                <Stack pos='relative' gap='xs'>
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='text'
 | 
				
			||||||
 | 
					                    name={t`Name`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.name}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='text'
 | 
				
			||||||
 | 
					                    name={t`Description`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.meta.description}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='text'
 | 
				
			||||||
 | 
					                    name={t`Author`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.meta.author}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='text'
 | 
				
			||||||
 | 
					                    name={t`Date`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.meta.pub_date}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='text'
 | 
				
			||||||
 | 
					                    name={t`Version`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.meta.version}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='boolean'
 | 
				
			||||||
 | 
					                    name={t`Active`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.active}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </Stack>
 | 
				
			||||||
 | 
					              </Stack>
 | 
				
			||||||
 | 
					            </Card>
 | 
				
			||||||
 | 
					            <Card withBorder>
 | 
				
			||||||
 | 
					              <Stack gap='md'>
 | 
				
			||||||
 | 
					                <Stack pos='relative' gap='xs'>
 | 
				
			||||||
 | 
					                  {pluginInstance?.is_package && (
 | 
				
			||||||
 | 
					                    <InfoItem
 | 
				
			||||||
 | 
					                      type='text'
 | 
				
			||||||
 | 
					                      name={t`Package Name`}
 | 
				
			||||||
 | 
					                      value={pluginInstance?.package_name}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='text'
 | 
				
			||||||
 | 
					                    name={t`Installation Path`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.meta.package_path}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='boolean'
 | 
				
			||||||
 | 
					                    name={t`Builtin`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.is_builtin}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <InfoItem
 | 
				
			||||||
 | 
					                    type='boolean'
 | 
				
			||||||
 | 
					                    name={t`Package`}
 | 
				
			||||||
 | 
					                    value={pluginInstance?.is_package}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </Stack>
 | 
				
			||||||
 | 
					              </Stack>
 | 
				
			||||||
 | 
					            </Card>
 | 
				
			||||||
 | 
					          </Stack>
 | 
				
			||||||
 | 
					        </Accordion.Panel>
 | 
				
			||||||
 | 
					      </Accordion.Item>
 | 
				
			||||||
 | 
					      {hasSettings && (
 | 
				
			||||||
 | 
					        <Accordion.Item value='plugin-settings'>
 | 
				
			||||||
          <Accordion.Control>
 | 
					          <Accordion.Control>
 | 
				
			||||||
            <StylishText size='lg'>{t`Plugin Information`}</StylishText>
 | 
					            <StylishText size='lg'>{t`Plugin Settings`}</StylishText>
 | 
				
			||||||
          </Accordion.Control>
 | 
					          </Accordion.Control>
 | 
				
			||||||
          <Accordion.Panel>
 | 
					          <Accordion.Panel>
 | 
				
			||||||
            <Stack gap='xs'>
 | 
					            <Card withBorder>
 | 
				
			||||||
              <Card withBorder>
 | 
					              <PluginSettingList pluginKey={pluginPrimaryKey} />
 | 
				
			||||||
                <Stack gap='md'>
 | 
					            </Card>
 | 
				
			||||||
                  <Stack pos='relative' gap='xs'>
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='text'
 | 
					 | 
				
			||||||
                      name={t`Name`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.name}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='text'
 | 
					 | 
				
			||||||
                      name={t`Description`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.meta.description}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='text'
 | 
					 | 
				
			||||||
                      name={t`Author`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.meta.author}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='text'
 | 
					 | 
				
			||||||
                      name={t`Date`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.meta.pub_date}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='text'
 | 
					 | 
				
			||||||
                      name={t`Version`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.meta.version}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='boolean'
 | 
					 | 
				
			||||||
                      name={t`Active`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.active}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                  </Stack>
 | 
					 | 
				
			||||||
                </Stack>
 | 
					 | 
				
			||||||
              </Card>
 | 
					 | 
				
			||||||
              <Card withBorder>
 | 
					 | 
				
			||||||
                <Stack gap='md'>
 | 
					 | 
				
			||||||
                  <Stack pos='relative' gap='xs'>
 | 
					 | 
				
			||||||
                    {pluginInstance?.is_package && (
 | 
					 | 
				
			||||||
                      <InfoItem
 | 
					 | 
				
			||||||
                        type='text'
 | 
					 | 
				
			||||||
                        name={t`Package Name`}
 | 
					 | 
				
			||||||
                        value={pluginInstance?.package_name}
 | 
					 | 
				
			||||||
                      />
 | 
					 | 
				
			||||||
                    )}
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='text'
 | 
					 | 
				
			||||||
                      name={t`Installation Path`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.meta.package_path}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='boolean'
 | 
					 | 
				
			||||||
                      name={t`Builtin`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.is_builtin}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <InfoItem
 | 
					 | 
				
			||||||
                      type='boolean'
 | 
					 | 
				
			||||||
                      name={t`Package`}
 | 
					 | 
				
			||||||
                      value={pluginInstance?.is_package}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                  </Stack>
 | 
					 | 
				
			||||||
                </Stack>
 | 
					 | 
				
			||||||
              </Card>
 | 
					 | 
				
			||||||
            </Stack>
 | 
					 | 
				
			||||||
          </Accordion.Panel>
 | 
					          </Accordion.Panel>
 | 
				
			||||||
        </Accordion.Item>
 | 
					        </Accordion.Item>
 | 
				
			||||||
        {hasSettings && (
 | 
					      )}
 | 
				
			||||||
          <Accordion.Item value='plugin-settings'>
 | 
					      {pluginAdmin?.source && (
 | 
				
			||||||
            <Accordion.Control>
 | 
					        <Accordion.Item value='plugin-custom'>
 | 
				
			||||||
              <StylishText size='lg'>{t`Plugin Settings`}</StylishText>
 | 
					          <Accordion.Control>
 | 
				
			||||||
            </Accordion.Control>
 | 
					            <StylishText size='lg'>{t`Plugin Configuration`}</StylishText>
 | 
				
			||||||
            <Accordion.Panel>
 | 
					          </Accordion.Control>
 | 
				
			||||||
              <Card withBorder>
 | 
					          <Accordion.Panel>
 | 
				
			||||||
                <PluginSettingList pluginKey={pluginPrimaryKey} />
 | 
					            <Card withBorder>
 | 
				
			||||||
              </Card>
 | 
					              <PluginSettingsPanel pluginAdmin={pluginAdmin} />
 | 
				
			||||||
            </Accordion.Panel>
 | 
					            </Card>
 | 
				
			||||||
          </Accordion.Item>
 | 
					          </Accordion.Panel>
 | 
				
			||||||
        )}
 | 
					        </Accordion.Item>
 | 
				
			||||||
        {pluginAdmin?.source && (
 | 
					      )}
 | 
				
			||||||
          <Accordion.Item value='plugin-custom'>
 | 
					    </Accordion>
 | 
				
			||||||
            <Accordion.Control>
 | 
					 | 
				
			||||||
              <StylishText size='lg'>{t`Plugin Configuration`}</StylishText>
 | 
					 | 
				
			||||||
            </Accordion.Control>
 | 
					 | 
				
			||||||
            <Accordion.Panel>
 | 
					 | 
				
			||||||
              <Card withBorder>
 | 
					 | 
				
			||||||
                <PluginSettingsPanel pluginAdmin={pluginAdmin} />
 | 
					 | 
				
			||||||
              </Card>
 | 
					 | 
				
			||||||
            </Accordion.Panel>
 | 
					 | 
				
			||||||
          </Accordion.Item>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </Accordion>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,9 +18,9 @@ export interface PluginAdminInterface {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export default function PluginSettingsPanel({
 | 
					export default function PluginSettingsPanel({
 | 
				
			||||||
  pluginAdmin
 | 
					  pluginAdmin
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  pluginAdmin: PluginAdminInterface;
 | 
					  pluginAdmin: PluginAdminInterface;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const pluginContext = useInvenTreeContext();
 | 
					  const pluginContext = useInvenTreeContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,11 +21,11 @@ export default function RemoteComponent({
 | 
				
			|||||||
  source,
 | 
					  source,
 | 
				
			||||||
  defaultFunctionName,
 | 
					  defaultFunctionName,
 | 
				
			||||||
  context
 | 
					  context
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  source: string;
 | 
					  source: string;
 | 
				
			||||||
  defaultFunctionName: string;
 | 
					  defaultFunctionName: string;
 | 
				
			||||||
  context: InvenTreeContext;
 | 
					  context: InvenTreeContext;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const componentRef = useRef<HTMLDivElement>();
 | 
					  const componentRef = useRef<HTMLDivElement>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [renderingError, setRenderingError] = useState<string | undefined>(
 | 
					  const [renderingError, setRenderingError] = useState<string | undefined>(
 | 
				
			||||||
@@ -78,28 +78,23 @@ export default function RemoteComponent({
 | 
				
			|||||||
  }, [sourceFile, functionName, context]);
 | 
					  }, [sourceFile, functionName, context]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <Boundary
 | 
				
			||||||
      <Boundary
 | 
					      label={identifierString(`RemoteComponent-${sourceFile}-${functionName}`)}
 | 
				
			||||||
        label={identifierString(
 | 
					    >
 | 
				
			||||||
          `RemoteComponent-${sourceFile}-${functionName}`
 | 
					      <Stack gap='xs'>
 | 
				
			||||||
 | 
					        {renderingError && (
 | 
				
			||||||
 | 
					          <Alert
 | 
				
			||||||
 | 
					            color='red'
 | 
				
			||||||
 | 
					            title={t`Error Loading Content`}
 | 
				
			||||||
 | 
					            icon={<IconExclamationCircle />}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Text>
 | 
				
			||||||
 | 
					              {t`Error occurred while loading plugin content`}: {renderingError}
 | 
				
			||||||
 | 
					            </Text>
 | 
				
			||||||
 | 
					          </Alert>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      >
 | 
					        <div ref={componentRef as any} />
 | 
				
			||||||
        <Stack gap='xs'>
 | 
					      </Stack>
 | 
				
			||||||
          {renderingError && (
 | 
					    </Boundary>
 | 
				
			||||||
            <Alert
 | 
					 | 
				
			||||||
              color='red'
 | 
					 | 
				
			||||||
              title={t`Error Loading Content`}
 | 
					 | 
				
			||||||
              icon={<IconExclamationCircle />}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <Text>
 | 
					 | 
				
			||||||
                {t`Error occurred while loading plugin content`}:{' '}
 | 
					 | 
				
			||||||
                {renderingError}
 | 
					 | 
				
			||||||
              </Text>
 | 
					 | 
				
			||||||
            </Alert>
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
          <div ref={componentRef as any} />
 | 
					 | 
				
			||||||
        </Stack>
 | 
					 | 
				
			||||||
      </Boundary>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -121,11 +121,11 @@ function SalesOrderAllocateLineRow({
 | 
				
			|||||||
  props,
 | 
					  props,
 | 
				
			||||||
  record,
 | 
					  record,
 | 
				
			||||||
  sourceLocation
 | 
					  sourceLocation
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  props: TableFieldRowProps;
 | 
					  props: TableFieldRowProps;
 | 
				
			||||||
  record: any;
 | 
					  record: any;
 | 
				
			||||||
  sourceLocation?: number | null;
 | 
					  sourceLocation?: number | null;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  // Statically defined field for selecting the stock item
 | 
					  // Statically defined field for selecting the stock item
 | 
				
			||||||
  const stockItemField: ApiFormFieldType = useMemo(() => {
 | 
					  const stockItemField: ApiFormFieldType = useMemo(() => {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
@@ -360,7 +360,7 @@ export function useSalesOrderAllocationFields({
 | 
				
			|||||||
  shipment
 | 
					  shipment
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
  orderId?: number;
 | 
					  orderId?: number;
 | 
				
			||||||
  shipment: any | null;
 | 
					  shipment: any;
 | 
				
			||||||
}): ApiFormFieldSet {
 | 
					}): ApiFormFieldSet {
 | 
				
			||||||
  return useMemo(() => {
 | 
					  return useMemo(() => {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,36 +7,34 @@ import { useUserState } from '../../states/UserState';
 | 
				
			|||||||
import PartBuildAllocationsTable from '../../tables/part/PartBuildAllocationsTable';
 | 
					import PartBuildAllocationsTable from '../../tables/part/PartBuildAllocationsTable';
 | 
				
			||||||
import PartSalesAllocationsTable from '../../tables/part/PartSalesAllocationsTable';
 | 
					import PartSalesAllocationsTable from '../../tables/part/PartSalesAllocationsTable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function PartAllocationPanel({ part }: { part: any }) {
 | 
					export default function PartAllocationPanel({ part }: Readonly<{ part: any }>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <Accordion
 | 
				
			||||||
      <Accordion
 | 
					      multiple={true}
 | 
				
			||||||
        multiple={true}
 | 
					      defaultValue={['buildallocations', 'salesallocations']}
 | 
				
			||||||
        defaultValue={['buildallocations', 'salesallocations']}
 | 
					    >
 | 
				
			||||||
      >
 | 
					      {part.component && user.hasViewRole(UserRoles.build) && (
 | 
				
			||||||
        {part.component && user.hasViewRole(UserRoles.build) && (
 | 
					        <Accordion.Item value='buildallocations' key='buildallocations'>
 | 
				
			||||||
          <Accordion.Item value='buildallocations' key='buildallocations'>
 | 
					          <Accordion.Control>
 | 
				
			||||||
            <Accordion.Control>
 | 
					            <StylishText size='lg'>{t`Build Order Allocations`}</StylishText>
 | 
				
			||||||
              <StylishText size='lg'>{t`Build Order Allocations`}</StylishText>
 | 
					          </Accordion.Control>
 | 
				
			||||||
            </Accordion.Control>
 | 
					          <Accordion.Panel>
 | 
				
			||||||
            <Accordion.Panel>
 | 
					            <PartBuildAllocationsTable partId={part.pk} />
 | 
				
			||||||
              <PartBuildAllocationsTable partId={part.pk} />
 | 
					          </Accordion.Panel>
 | 
				
			||||||
            </Accordion.Panel>
 | 
					        </Accordion.Item>
 | 
				
			||||||
          </Accordion.Item>
 | 
					      )}
 | 
				
			||||||
        )}
 | 
					      {part.salable && user.hasViewRole(UserRoles.sales_order) && (
 | 
				
			||||||
        {part.salable && user.hasViewRole(UserRoles.sales_order) && (
 | 
					        <Accordion.Item value='salesallocations' key='salesallocations'>
 | 
				
			||||||
          <Accordion.Item value='salesallocations' key='salesallocations'>
 | 
					          <Accordion.Control>
 | 
				
			||||||
            <Accordion.Control>
 | 
					            <StylishText size='lg'>{t`Sales Order Allocations`}</StylishText>
 | 
				
			||||||
              <StylishText size='lg'>{t`Sales Order Allocations`}</StylishText>
 | 
					          </Accordion.Control>
 | 
				
			||||||
            </Accordion.Control>
 | 
					          <Accordion.Panel>
 | 
				
			||||||
            <Accordion.Panel>
 | 
					            <PartSalesAllocationsTable partId={part.pk} />
 | 
				
			||||||
              <PartSalesAllocationsTable partId={part.pk} />
 | 
					          </Accordion.Panel>
 | 
				
			||||||
            </Accordion.Panel>
 | 
					        </Accordion.Item>
 | 
				
			||||||
          </Accordion.Item>
 | 
					      )}
 | 
				
			||||||
        )}
 | 
					    </Accordion>
 | 
				
			||||||
      </Accordion>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ import { TableHoverCard } from '../../tables/TableHoverCard';
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Render a tooltip for the chart, with correct date information
 | 
					 * Render a tooltip for the chart, with correct date information
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function ChartTooltip({ label, payload }: ChartTooltipProps) {
 | 
					function ChartTooltip({ label, payload }: Readonly<ChartTooltipProps>) {
 | 
				
			||||||
  if (!payload) {
 | 
					  if (!payload) {
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -56,7 +56,9 @@ function ChartTooltip({ label, payload }: ChartTooltipProps) {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function PartSchedulingDetail({ part }: { part: any }) {
 | 
					export default function PartSchedulingDetail({
 | 
				
			||||||
 | 
					  part
 | 
				
			||||||
 | 
					}: Readonly<{ part: any }>) {
 | 
				
			||||||
  const table = useTable('part-scheduling');
 | 
					  const table = useTable('part-scheduling');
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ import { RowDeleteAction, RowEditAction } from '../../tables/RowActions';
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Render a tooltip for the chart, with correct date information
 | 
					 * Render a tooltip for the chart, with correct date information
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function ChartTooltip({ label, payload }: ChartTooltipProps) {
 | 
					function ChartTooltip({ label, payload }: Readonly<ChartTooltipProps>) {
 | 
				
			||||||
  const formattedLabel: string = useMemo(() => {
 | 
					  const formattedLabel: string = useMemo(() => {
 | 
				
			||||||
    if (label && typeof label === 'number') {
 | 
					    if (label && typeof label === 'number') {
 | 
				
			||||||
      return formatDate(new Date(label).toISOString()) ?? label;
 | 
					      return formatDate(new Date(label).toISOString()) ?? label;
 | 
				
			||||||
@@ -66,7 +66,9 @@ function ChartTooltip({ label, payload }: ChartTooltipProps) {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function PartStocktakeDetail({ partId }: { partId: number }) {
 | 
					export default function PartStocktakeDetail({
 | 
				
			||||||
 | 
					  partId
 | 
				
			||||||
 | 
					}: Readonly<{ partId: number }>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const table = useTable('part-stocktake');
 | 
					  const table = useTable('part-stocktake');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,9 @@ import { StylishText } from '../../components/items/StylishText';
 | 
				
			|||||||
import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
 | 
					import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
 | 
				
			||||||
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
 | 
					import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function PartSupplierDetail({ partId }: { partId: number }) {
 | 
					export default function PartSupplierDetail({
 | 
				
			||||||
 | 
					  partId
 | 
				
			||||||
 | 
					}: Readonly<{ partId: number }>) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Accordion multiple defaultValue={['part-suppliers', 'part-manufacturers']}>
 | 
					    <Accordion multiple defaultValue={['part-suppliers', 'part-manufacturers']}>
 | 
				
			||||||
      <Accordion.Item value='part-suppliers'>
 | 
					      <Accordion.Item value='part-suppliers'>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@ export default function InvenTreeTableHeader({
 | 
				
			|||||||
  columns,
 | 
					  columns,
 | 
				
			||||||
  filters,
 | 
					  filters,
 | 
				
			||||||
  toggleColumn
 | 
					  toggleColumn
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  tableUrl: string;
 | 
					  tableUrl: string;
 | 
				
			||||||
  tableState: TableState;
 | 
					  tableState: TableState;
 | 
				
			||||||
  tableProps: InvenTreeTableProps<any>;
 | 
					  tableProps: InvenTreeTableProps<any>;
 | 
				
			||||||
@@ -49,7 +49,7 @@ export default function InvenTreeTableHeader({
 | 
				
			|||||||
  columns: any;
 | 
					  columns: any;
 | 
				
			||||||
  filters: TableFilter[];
 | 
					  filters: TableFilter[];
 | 
				
			||||||
  toggleColumn: (column: string) => void;
 | 
					  toggleColumn: (column: string) => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  // Filter list visibility
 | 
					  // Filter list visibility
 | 
				
			||||||
  const [filtersVisible, setFiltersVisible] = useState<boolean>(false);
 | 
					  const [filtersVisible, setFiltersVisible] = useState<boolean>(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,10 @@ import { IconChevronDown, IconChevronRight } from '@tabler/icons-react';
 | 
				
			|||||||
export default function RowExpansionIcon({
 | 
					export default function RowExpansionIcon({
 | 
				
			||||||
  enabled,
 | 
					  enabled,
 | 
				
			||||||
  expanded
 | 
					  expanded
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  enabled: boolean;
 | 
					  enabled: boolean;
 | 
				
			||||||
  expanded: boolean;
 | 
					  expanded: boolean;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <ActionIcon size='sm' variant='transparent' disabled={!enabled}>
 | 
					    <ActionIcon size='sm' variant='transparent' disabled={!enabled}>
 | 
				
			||||||
      {expanded ? <IconChevronDown /> : <IconChevronRight />}
 | 
					      {expanded ? <IconChevronDown /> : <IconChevronRight />}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,11 +56,11 @@ export function BuildLineSubTable({
 | 
				
			|||||||
  lineItem,
 | 
					  lineItem,
 | 
				
			||||||
  onEditAllocation,
 | 
					  onEditAllocation,
 | 
				
			||||||
  onDeleteAllocation
 | 
					  onDeleteAllocation
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  lineItem: any;
 | 
					  lineItem: any;
 | 
				
			||||||
  onEditAllocation?: (pk: number) => void;
 | 
					  onEditAllocation?: (pk: number) => void;
 | 
				
			||||||
  onDeleteAllocation?: (pk: number) => void;
 | 
					  onDeleteAllocation?: (pk: number) => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,61 +61,59 @@ function OutputAllocationDrawer({
 | 
				
			|||||||
  output,
 | 
					  output,
 | 
				
			||||||
  opened,
 | 
					  opened,
 | 
				
			||||||
  close
 | 
					  close
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  build: any;
 | 
					  build: any;
 | 
				
			||||||
  output: any;
 | 
					  output: any;
 | 
				
			||||||
  opened: boolean;
 | 
					  opened: boolean;
 | 
				
			||||||
  close: () => void;
 | 
					  close: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <Drawer
 | 
				
			||||||
      <Drawer
 | 
					      position='bottom'
 | 
				
			||||||
        position='bottom'
 | 
					      size='lg'
 | 
				
			||||||
        size='lg'
 | 
					      title={
 | 
				
			||||||
        title={
 | 
					        <Group p='md' wrap='nowrap' justify='space-apart'>
 | 
				
			||||||
          <Group p='md' wrap='nowrap' justify='space-apart'>
 | 
					          <StylishText size='lg'>{t`Build Output Stock Allocation`}</StylishText>
 | 
				
			||||||
            <StylishText size='lg'>{t`Build Output Stock Allocation`}</StylishText>
 | 
					          <Space h='lg' />
 | 
				
			||||||
            <Space h='lg' />
 | 
					          <PartColumn part={build.part_detail} />
 | 
				
			||||||
            <PartColumn part={build.part_detail} />
 | 
					          {output?.serial && (
 | 
				
			||||||
            {output?.serial && (
 | 
					            <Text size='sm'>
 | 
				
			||||||
              <Text size='sm'>
 | 
					              {t`Serial Number`}: {output.serial}
 | 
				
			||||||
                {t`Serial Number`}: {output.serial}
 | 
					            </Text>
 | 
				
			||||||
              </Text>
 | 
					          )}
 | 
				
			||||||
            )}
 | 
					          {output?.batch && (
 | 
				
			||||||
            {output?.batch && (
 | 
					            <Text size='sm'>
 | 
				
			||||||
              <Text size='sm'>
 | 
					              {t`Batch Code`}: {output.batch}
 | 
				
			||||||
                {t`Batch Code`}: {output.batch}
 | 
					            </Text>
 | 
				
			||||||
              </Text>
 | 
					          )}
 | 
				
			||||||
            )}
 | 
					          <Space h='lg' />
 | 
				
			||||||
            <Space h='lg' />
 | 
					        </Group>
 | 
				
			||||||
          </Group>
 | 
					      }
 | 
				
			||||||
 | 
					      opened={opened}
 | 
				
			||||||
 | 
					      onClose={close}
 | 
				
			||||||
 | 
					      withCloseButton
 | 
				
			||||||
 | 
					      closeOnEscape
 | 
				
			||||||
 | 
					      closeOnClickOutside
 | 
				
			||||||
 | 
					      styles={{
 | 
				
			||||||
 | 
					        header: {
 | 
				
			||||||
 | 
					          width: '100%'
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					          width: '100%'
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        opened={opened}
 | 
					      }}
 | 
				
			||||||
        onClose={close}
 | 
					    >
 | 
				
			||||||
        withCloseButton
 | 
					      <Divider />
 | 
				
			||||||
        closeOnEscape
 | 
					      <Paper p='md'>
 | 
				
			||||||
        closeOnClickOutside
 | 
					        <BuildLineTable
 | 
				
			||||||
        styles={{
 | 
					          build={build}
 | 
				
			||||||
          header: {
 | 
					          output={output}
 | 
				
			||||||
            width: '100%'
 | 
					          params={{
 | 
				
			||||||
          },
 | 
					            tracked: true
 | 
				
			||||||
          title: {
 | 
					          }}
 | 
				
			||||||
            width: '100%'
 | 
					        />
 | 
				
			||||||
          }
 | 
					      </Paper>
 | 
				
			||||||
        }}
 | 
					    </Drawer>
 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <Divider />
 | 
					 | 
				
			||||||
        <Paper p='md'>
 | 
					 | 
				
			||||||
          <BuildLineTable
 | 
					 | 
				
			||||||
            build={build}
 | 
					 | 
				
			||||||
            output={output}
 | 
					 | 
				
			||||||
            params={{
 | 
					 | 
				
			||||||
              tracked: true
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </Paper>
 | 
					 | 
				
			||||||
      </Drawer>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,9 +27,9 @@ import { BuildLineSubTable } from '../build/BuildLineTable';
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export default function PartBuildAllocationsTable({
 | 
					export default function PartBuildAllocationsTable({
 | 
				
			||||||
  partId
 | 
					  partId
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  partId: number;
 | 
					  partId: number;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
  const table = useTable('part-build-allocations');
 | 
					  const table = useTable('part-build-allocations');
 | 
				
			||||||
@@ -106,25 +106,23 @@ export default function PartBuildAllocationsTable({
 | 
				
			|||||||
  }, [table.isRowExpanded]);
 | 
					  }, [table.isRowExpanded]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <InvenTreeTable
 | 
				
			||||||
      <InvenTreeTable
 | 
					      url={apiUrl(ApiEndpoints.build_line_list)}
 | 
				
			||||||
        url={apiUrl(ApiEndpoints.build_line_list)}
 | 
					      tableState={table}
 | 
				
			||||||
        tableState={table}
 | 
					      columns={tableColumns}
 | 
				
			||||||
        columns={tableColumns}
 | 
					      props={{
 | 
				
			||||||
        props={{
 | 
					        minHeight: 200,
 | 
				
			||||||
          minHeight: 200,
 | 
					        params: {
 | 
				
			||||||
          params: {
 | 
					          part: partId,
 | 
				
			||||||
            part: partId,
 | 
					          consumable: false,
 | 
				
			||||||
            consumable: false,
 | 
					          build_detail: true,
 | 
				
			||||||
            build_detail: true,
 | 
					          order_outstanding: true
 | 
				
			||||||
            order_outstanding: true
 | 
					        },
 | 
				
			||||||
          },
 | 
					        enableColumnSwitching: false,
 | 
				
			||||||
          enableColumnSwitching: false,
 | 
					        enableSearch: false,
 | 
				
			||||||
          enableSearch: false,
 | 
					        rowActions: rowActions,
 | 
				
			||||||
          rowActions: rowActions,
 | 
					        rowExpansion: rowExpansion
 | 
				
			||||||
          rowExpansion: rowExpansion
 | 
					      }}
 | 
				
			||||||
        }}
 | 
					    />
 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,9 +24,9 @@ import SalesOrderAllocationTable from '../sales/SalesOrderAllocationTable';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default function PartSalesAllocationsTable({
 | 
					export default function PartSalesAllocationsTable({
 | 
				
			||||||
  partId
 | 
					  partId
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  partId: number;
 | 
					  partId: number;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const navigate = useNavigate();
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
  const table = useTable('part-sales-allocations');
 | 
					  const table = useTable('part-sales-allocations');
 | 
				
			||||||
@@ -109,24 +109,22 @@ export default function PartSalesAllocationsTable({
 | 
				
			|||||||
  }, [table.isRowExpanded]);
 | 
					  }, [table.isRowExpanded]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <InvenTreeTable
 | 
				
			||||||
      <InvenTreeTable
 | 
					      url={apiUrl(ApiEndpoints.sales_order_line_list)}
 | 
				
			||||||
        url={apiUrl(ApiEndpoints.sales_order_line_list)}
 | 
					      tableState={table}
 | 
				
			||||||
        tableState={table}
 | 
					      columns={tableColumns}
 | 
				
			||||||
        columns={tableColumns}
 | 
					      props={{
 | 
				
			||||||
        props={{
 | 
					        minHeight: 200,
 | 
				
			||||||
          minHeight: 200,
 | 
					        params: {
 | 
				
			||||||
          params: {
 | 
					          part: partId,
 | 
				
			||||||
            part: partId,
 | 
					          order_detail: true,
 | 
				
			||||||
            order_detail: true,
 | 
					          order_outstanding: true
 | 
				
			||||||
            order_outstanding: true
 | 
					        },
 | 
				
			||||||
          },
 | 
					        enableSearch: false,
 | 
				
			||||||
          enableSearch: false,
 | 
					        enableColumnSwitching: false,
 | 
				
			||||||
          enableColumnSwitching: false,
 | 
					        rowExpansion: rowExpansion,
 | 
				
			||||||
          rowExpansion: rowExpansion,
 | 
					        rowActions: rowActions
 | 
				
			||||||
          rowActions: rowActions
 | 
					      }}
 | 
				
			||||||
        }}
 | 
					    />
 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ import { RowDeleteAction } from '../RowActions';
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Render detail information for a particular barcode scan result.
 | 
					 * Render detail information for a particular barcode scan result.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function BarcodeScanDetail({ scan }: { scan: any }) {
 | 
					function BarcodeScanDetail({ scan }: Readonly<{ scan: any }>) {
 | 
				
			||||||
  const dataStyle: MantineStyleProp = {
 | 
					  const dataStyle: MantineStyleProp = {
 | 
				
			||||||
    textWrap: 'wrap',
 | 
					    textWrap: 'wrap',
 | 
				
			||||||
    lineBreak: 'auto',
 | 
					    lineBreak: 'auto',
 | 
				
			||||||
@@ -51,93 +51,91 @@ function BarcodeScanDetail({ scan }: { scan: any }) {
 | 
				
			|||||||
  }, [scan.context]);
 | 
					  }, [scan.context]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <Stack gap='xs'>
 | 
				
			||||||
      <Stack gap='xs'>
 | 
					      <Divider />
 | 
				
			||||||
        <Divider />
 | 
					      <Table>
 | 
				
			||||||
        <Table>
 | 
					        <Table.Tbody>
 | 
				
			||||||
          <Table.Tbody>
 | 
					          <Table.Tr>
 | 
				
			||||||
 | 
					            <Table.Td colSpan={2}>
 | 
				
			||||||
 | 
					              <StylishText size='sm'>{t`Barcode Information`}</StylishText>
 | 
				
			||||||
 | 
					            </Table.Td>
 | 
				
			||||||
 | 
					          </Table.Tr>
 | 
				
			||||||
 | 
					          <Table.Tr>
 | 
				
			||||||
 | 
					            <Table.Th>{t`Barcode`}</Table.Th>
 | 
				
			||||||
 | 
					            <Table.Td>
 | 
				
			||||||
 | 
					              <Text size='sm' style={dataStyle}>
 | 
				
			||||||
 | 
					                {scan.data}
 | 
				
			||||||
 | 
					              </Text>
 | 
				
			||||||
 | 
					            </Table.Td>
 | 
				
			||||||
 | 
					            <Table.Td>
 | 
				
			||||||
 | 
					              <CopyButton value={scan.data} size='xs' />
 | 
				
			||||||
 | 
					            </Table.Td>
 | 
				
			||||||
 | 
					          </Table.Tr>
 | 
				
			||||||
 | 
					          <Table.Tr>
 | 
				
			||||||
 | 
					            <Table.Th>{t`Timestamp`}</Table.Th>
 | 
				
			||||||
 | 
					            <Table.Td>{scan.timestamp}</Table.Td>
 | 
				
			||||||
 | 
					          </Table.Tr>
 | 
				
			||||||
 | 
					          <Table.Tr>
 | 
				
			||||||
 | 
					            <Table.Th>{t`User`}</Table.Th>
 | 
				
			||||||
 | 
					            <Table.Td>
 | 
				
			||||||
 | 
					              <RenderUser instance={scan.user_detail} />
 | 
				
			||||||
 | 
					            </Table.Td>
 | 
				
			||||||
 | 
					          </Table.Tr>
 | 
				
			||||||
 | 
					          <Table.Tr>
 | 
				
			||||||
 | 
					            <Table.Th>{t`Endpoint`}</Table.Th>
 | 
				
			||||||
 | 
					            <Table.Td>{scan.endpoint}</Table.Td>
 | 
				
			||||||
 | 
					          </Table.Tr>
 | 
				
			||||||
 | 
					          <Table.Tr>
 | 
				
			||||||
 | 
					            <Table.Th>{t`Result`}</Table.Th>
 | 
				
			||||||
 | 
					            <Table.Td>
 | 
				
			||||||
 | 
					              <PassFailButton value={scan.result} />
 | 
				
			||||||
 | 
					            </Table.Td>
 | 
				
			||||||
 | 
					          </Table.Tr>
 | 
				
			||||||
 | 
					          {hasContextData && (
 | 
				
			||||||
            <Table.Tr>
 | 
					            <Table.Tr>
 | 
				
			||||||
              <Table.Td colSpan={2}>
 | 
					              <Table.Td colSpan={2}>
 | 
				
			||||||
                <StylishText size='sm'>{t`Barcode Information`}</StylishText>
 | 
					                <StylishText size='sm'>{t`Context`}</StylishText>
 | 
				
			||||||
              </Table.Td>
 | 
					              </Table.Td>
 | 
				
			||||||
            </Table.Tr>
 | 
					            </Table.Tr>
 | 
				
			||||||
            <Table.Tr>
 | 
					          )}
 | 
				
			||||||
              <Table.Th>{t`Barcode`}</Table.Th>
 | 
					          {hasContextData &&
 | 
				
			||||||
              <Table.Td>
 | 
					            Object.keys(scan.context).map((key) => (
 | 
				
			||||||
                <Text size='sm' style={dataStyle}>
 | 
					              <Table.Tr key={key}>
 | 
				
			||||||
                  {scan.data}
 | 
					                <Table.Th>{key}</Table.Th>
 | 
				
			||||||
                </Text>
 | 
					                <Table.Td>
 | 
				
			||||||
              </Table.Td>
 | 
					                  <Text size='sm' style={dataStyle}>
 | 
				
			||||||
              <Table.Td>
 | 
					                    {scan.context[key]}
 | 
				
			||||||
                <CopyButton value={scan.data} size='xs' />
 | 
					                  </Text>
 | 
				
			||||||
              </Table.Td>
 | 
					                </Table.Td>
 | 
				
			||||||
            </Table.Tr>
 | 
					                <Table.Td>
 | 
				
			||||||
            <Table.Tr>
 | 
					                  <CopyButton value={scan.context[key]} size='xs' />
 | 
				
			||||||
              <Table.Th>{t`Timestamp`}</Table.Th>
 | 
					 | 
				
			||||||
              <Table.Td>{scan.timestamp}</Table.Td>
 | 
					 | 
				
			||||||
            </Table.Tr>
 | 
					 | 
				
			||||||
            <Table.Tr>
 | 
					 | 
				
			||||||
              <Table.Th>{t`User`}</Table.Th>
 | 
					 | 
				
			||||||
              <Table.Td>
 | 
					 | 
				
			||||||
                <RenderUser instance={scan.user_detail} />
 | 
					 | 
				
			||||||
              </Table.Td>
 | 
					 | 
				
			||||||
            </Table.Tr>
 | 
					 | 
				
			||||||
            <Table.Tr>
 | 
					 | 
				
			||||||
              <Table.Th>{t`Endpoint`}</Table.Th>
 | 
					 | 
				
			||||||
              <Table.Td>{scan.endpoint}</Table.Td>
 | 
					 | 
				
			||||||
            </Table.Tr>
 | 
					 | 
				
			||||||
            <Table.Tr>
 | 
					 | 
				
			||||||
              <Table.Th>{t`Result`}</Table.Th>
 | 
					 | 
				
			||||||
              <Table.Td>
 | 
					 | 
				
			||||||
                <PassFailButton value={scan.result} />
 | 
					 | 
				
			||||||
              </Table.Td>
 | 
					 | 
				
			||||||
            </Table.Tr>
 | 
					 | 
				
			||||||
            {hasContextData && (
 | 
					 | 
				
			||||||
              <Table.Tr>
 | 
					 | 
				
			||||||
                <Table.Td colSpan={2}>
 | 
					 | 
				
			||||||
                  <StylishText size='sm'>{t`Context`}</StylishText>
 | 
					 | 
				
			||||||
                </Table.Td>
 | 
					                </Table.Td>
 | 
				
			||||||
              </Table.Tr>
 | 
					              </Table.Tr>
 | 
				
			||||||
            )}
 | 
					            ))}
 | 
				
			||||||
            {hasContextData &&
 | 
					          {hasResponseData && (
 | 
				
			||||||
              Object.keys(scan.context).map((key) => (
 | 
					            <Table.Tr>
 | 
				
			||||||
                <Table.Tr key={key}>
 | 
					              <Table.Td colSpan={2}>
 | 
				
			||||||
                  <Table.Th>{key}</Table.Th>
 | 
					                <StylishText size='sm'>{t`Response`}</StylishText>
 | 
				
			||||||
                  <Table.Td>
 | 
					              </Table.Td>
 | 
				
			||||||
                    <Text size='sm' style={dataStyle}>
 | 
					            </Table.Tr>
 | 
				
			||||||
                      {scan.context[key]}
 | 
					          )}
 | 
				
			||||||
                    </Text>
 | 
					          {hasResponseData &&
 | 
				
			||||||
                  </Table.Td>
 | 
					            Object.keys(scan.response).map((key) => (
 | 
				
			||||||
                  <Table.Td>
 | 
					              <Table.Tr key={key}>
 | 
				
			||||||
                    <CopyButton value={scan.context[key]} size='xs' />
 | 
					                <Table.Th>{key}</Table.Th>
 | 
				
			||||||
                  </Table.Td>
 | 
					                <Table.Td>
 | 
				
			||||||
                </Table.Tr>
 | 
					                  <Text size='sm' style={dataStyle}>
 | 
				
			||||||
              ))}
 | 
					                    {scan.response[key]}
 | 
				
			||||||
            {hasResponseData && (
 | 
					                  </Text>
 | 
				
			||||||
              <Table.Tr>
 | 
					                </Table.Td>
 | 
				
			||||||
                <Table.Td colSpan={2}>
 | 
					                <Table.Td>
 | 
				
			||||||
                  <StylishText size='sm'>{t`Response`}</StylishText>
 | 
					                  <CopyButton value={scan.response[key]} size='xs' />
 | 
				
			||||||
                </Table.Td>
 | 
					                </Table.Td>
 | 
				
			||||||
              </Table.Tr>
 | 
					              </Table.Tr>
 | 
				
			||||||
            )}
 | 
					            ))}
 | 
				
			||||||
            {hasResponseData &&
 | 
					        </Table.Tbody>
 | 
				
			||||||
              Object.keys(scan.response).map((key) => (
 | 
					      </Table>
 | 
				
			||||||
                <Table.Tr key={key}>
 | 
					    </Stack>
 | 
				
			||||||
                  <Table.Th>{key}</Table.Th>
 | 
					 | 
				
			||||||
                  <Table.Td>
 | 
					 | 
				
			||||||
                    <Text size='sm' style={dataStyle}>
 | 
					 | 
				
			||||||
                      {scan.response[key]}
 | 
					 | 
				
			||||||
                    </Text>
 | 
					 | 
				
			||||||
                  </Table.Td>
 | 
					 | 
				
			||||||
                  <Table.Td>
 | 
					 | 
				
			||||||
                    <CopyButton value={scan.response[key]} size='xs' />
 | 
					 | 
				
			||||||
                  </Table.Td>
 | 
					 | 
				
			||||||
                </Table.Tr>
 | 
					 | 
				
			||||||
              ))}
 | 
					 | 
				
			||||||
          </Table.Tbody>
 | 
					 | 
				
			||||||
        </Table>
 | 
					 | 
				
			||||||
      </Stack>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ import type { TableColumn } from '../Column';
 | 
				
			|||||||
import { InvenTreeTable } from '../InvenTreeTable';
 | 
					import { InvenTreeTable } from '../InvenTreeTable';
 | 
				
			||||||
import { type RowAction, RowDeleteAction } from '../RowActions';
 | 
					import { type RowAction, RowDeleteAction } from '../RowActions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function ErrorDetail({ errorId }: { errorId?: number }) {
 | 
					function ErrorDetail({ errorId }: Readonly<{ errorId?: number }>) {
 | 
				
			||||||
  const { id } = useParams();
 | 
					  const { id } = useParams();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const errorPrimaryKey = useMemo(() => {
 | 
					  const errorPrimaryKey = useMemo(() => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,9 +15,9 @@ import { InvenTreeTable } from '../InvenTreeTable';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default function FailedTasksTable({
 | 
					export default function FailedTasksTable({
 | 
				
			||||||
  onRecordsUpdated
 | 
					  onRecordsUpdated
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  onRecordsUpdated: () => void;
 | 
					  onRecordsUpdated: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const table = useTable('tasks-failed');
 | 
					  const table = useTable('tasks-failed');
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,9 +10,9 @@ import { InvenTreeTable } from '../InvenTreeTable';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default function PendingTasksTable({
 | 
					export default function PendingTasksTable({
 | 
				
			||||||
  onRecordsUpdated
 | 
					  onRecordsUpdated
 | 
				
			||||||
}: {
 | 
					}: Readonly<{
 | 
				
			||||||
  onRecordsUpdated: () => void;
 | 
					  onRecordsUpdated: () => void;
 | 
				
			||||||
}) {
 | 
					}>) {
 | 
				
			||||||
  const table = useTable('tasks-pending');
 | 
					  const table = useTable('tasks-pending');
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user