2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 20:16:44 +00:00

[PUI] Make actions recognisable (#8005)

* Make dropdowns better recogniseable
Closes https://github.com/invenhost/InvenTree/issues/98

* change to button with section

* only draw border if needed

* allign drowdowns in header

* use light instead of subtle

* refactor option dropdowns to reduce duplications
This commit is contained in:
Matthias Mair 2024-09-03 05:01:29 +02:00 committed by GitHub
parent d81d1688bf
commit 355b4937da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 79 additions and 69 deletions

View File

@ -80,6 +80,7 @@ export default function AdminButton(props: AdminButtonProps) {
tooltip={t`Open in admin interface`} tooltip={t`Open in admin interface`}
hidden={!enabled} hidden={!enabled}
onClick={openAdmin} onClick={openAdmin}
tooltipAlignment="bottom"
/> />
); );
} }

View File

@ -1,6 +1,6 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
ActionIcon, Button,
Indicator, Indicator,
IndicatorProps, IndicatorProps,
Menu, Menu,
@ -8,7 +8,9 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { modals } from '@mantine/modals'; import { modals } from '@mantine/modals';
import { import {
IconChevronDown,
IconCopy, IconCopy,
IconDotsVertical,
IconEdit, IconEdit,
IconLink, IconLink,
IconQrcode, IconQrcode,
@ -42,13 +44,15 @@ export function ActionDropdown({
tooltip, tooltip,
actions, actions,
disabled = false, disabled = false,
hidden = false hidden = false,
noindicator = false
}: { }: {
icon: ReactNode; icon: ReactNode;
tooltip: string; tooltip: string;
actions: ActionDropdownItem[]; actions: ActionDropdownItem[];
disabled?: boolean; disabled?: boolean;
hidden?: boolean; hidden?: boolean;
noindicator?: boolean;
}) { }) {
const hasActions = useMemo(() => { const hasActions = useMemo(() => {
return actions.some((action) => !action.hidden); return actions.some((action) => !action.hidden);
@ -66,16 +70,25 @@ export function ActionDropdown({
<Menu position="bottom-end" key={menuName}> <Menu position="bottom-end" key={menuName}>
<Indicator disabled={!indicatorProps} {...indicatorProps?.indicator}> <Indicator disabled={!indicatorProps} {...indicatorProps?.indicator}>
<Menu.Target> <Menu.Target>
<Tooltip label={tooltip} hidden={!tooltip}> <Tooltip label={tooltip} hidden={!tooltip} position="bottom">
<ActionIcon <Button
size="lg"
radius="sm" radius="sm"
variant="transparent" variant={noindicator ? 'transparent' : 'light'}
disabled={disabled} disabled={disabled}
aria-label={menuName} aria-label={menuName}
p="0"
size="sm"
rightSection={
noindicator || disabled ? null : (
<IconChevronDown stroke={1.5} />
)
}
styles={{
section: { margin: 0 }
}}
> >
{icon} {icon}
</ActionIcon> </Button>
</Tooltip> </Tooltip>
</Menu.Target> </Menu.Target>
</Indicator> </Indicator>
@ -110,6 +123,26 @@ export function ActionDropdown({
) : null; ) : null;
} }
export function OptionsActionDropdown({
actions = [],
tooltip = t`Options`,
hidden = false
}: {
actions: ActionDropdownItem[];
tooltip?: string;
hidden?: boolean;
}) {
return (
<ActionDropdown
icon={<IconDotsVertical />}
tooltip={tooltip}
actions={actions}
hidden={hidden}
noindicator
/>
);
}
// Dropdown menu for barcode actions // Dropdown menu for barcode actions
export function BarcodeActionDropdown({ export function BarcodeActionDropdown({
model, model,

View File

@ -4,7 +4,6 @@ import {
IconChecklist, IconChecklist,
IconClipboardCheck, IconClipboardCheck,
IconClipboardList, IconClipboardList,
IconDots,
IconInfoCircle, IconInfoCircle,
IconList, IconList,
IconListCheck, IconListCheck,
@ -25,12 +24,12 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
BarcodeActionDropdown, BarcodeActionDropdown,
CancelItemAction, CancelItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction, EditItemAction,
HoldItemAction HoldItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
@ -474,9 +473,8 @@ export default function BuildDetail() {
items={[build.pk]} items={[build.pk]}
enableReports enableReports
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Build Order Actions`} tooltip={t`Build Order Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
onClick: () => editBuild.open(), onClick: () => editBuild.open(),

View File

@ -3,7 +3,6 @@ import { Grid, Skeleton, Stack } from '@mantine/core';
import { import {
IconBuildingFactory2, IconBuildingFactory2,
IconBuildingWarehouse, IconBuildingWarehouse,
IconDots,
IconInfoCircle, IconInfoCircle,
IconMap2, IconMap2,
IconNotes, IconNotes,
@ -25,9 +24,9 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
DeleteItemAction, DeleteItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { Breadcrumb } from '../../components/nav/BreadcrumbList'; import { Breadcrumb } from '../../components/nav/BreadcrumbList';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -302,9 +301,8 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
const companyActions = useMemo(() => { const companyActions = useMemo(() => {
return [ return [
<AdminButton model={ModelType.company} pk={company.pk} />, <AdminButton model={ModelType.company} pk={company.pk} />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Company Actions`} tooltip={t`Company Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
hidden: !user.hasChangeRole(UserRoles.purchase_order), hidden: !user.hasChangeRole(UserRoles.purchase_order),

View File

@ -2,7 +2,6 @@ import { t } from '@lingui/macro';
import { Grid, Skeleton, Stack } from '@mantine/core'; import { Grid, Skeleton, Stack } from '@mantine/core';
import { import {
IconBuildingWarehouse, IconBuildingWarehouse,
IconDots,
IconInfoCircle, IconInfoCircle,
IconList, IconList,
IconNotes, IconNotes,
@ -17,10 +16,10 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
DeleteItemAction, DeleteItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
@ -236,9 +235,8 @@ export default function ManufacturerPartDetail() {
model={ModelType.manufacturerpart} model={ModelType.manufacturerpart}
pk={manufacturerPart.pk} pk={manufacturerPart.pk}
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Manufacturer Part Actions`} tooltip={t`Manufacturer Part Actions`}
icon={<IconDots />}
actions={[ actions={[
DuplicateItemAction({ DuplicateItemAction({
hidden: !user.hasAddRole(UserRoles.purchase_order), hidden: !user.hasAddRole(UserRoles.purchase_order),

View File

@ -2,7 +2,6 @@ import { t } from '@lingui/macro';
import { Grid, Skeleton, Stack } from '@mantine/core'; import { Grid, Skeleton, Stack } from '@mantine/core';
import { import {
IconCurrencyDollar, IconCurrencyDollar,
IconDots,
IconInfoCircle, IconInfoCircle,
IconNotes, IconNotes,
IconPackages, IconPackages,
@ -18,11 +17,11 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
BarcodeActionDropdown, BarcodeActionDropdown,
DeleteItemAction, DeleteItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
@ -272,9 +271,8 @@ export default function SupplierPartDetail() {
hash={supplierPart.barcode_hash} hash={supplierPart.barcode_hash}
perm={user.hasChangeRole(UserRoles.purchase_order)} perm={user.hasChangeRole(UserRoles.purchase_order)}
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Supplier Part Actions`} tooltip={t`Supplier Part Actions`}
icon={<IconDots />}
actions={[ actions={[
DuplicateItemAction({ DuplicateItemAction({
hidden: !user.hasAddRole(UserRoles.purchase_order), hidden: !user.hasAddRole(UserRoles.purchase_order),

View File

@ -2,7 +2,6 @@ import { t } from '@lingui/macro';
import { Group, LoadingOverlay, Skeleton, Stack, Text } from '@mantine/core'; import { Group, LoadingOverlay, Skeleton, Stack, Text } from '@mantine/core';
import { import {
IconCategory, IconCategory,
IconDots,
IconInfoCircle, IconInfoCircle,
IconListDetails, IconListDetails,
IconSitemap IconSitemap
@ -14,9 +13,9 @@ import AdminButton from '../../components/buttons/AdminButton';
import { DetailsField, DetailsTable } from '../../components/details/Details'; import { DetailsField, DetailsTable } from '../../components/details/Details';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import { import {
ActionDropdown,
DeleteItemAction, DeleteItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { ApiIcon } from '../../components/items/ApiIcon'; import { ApiIcon } from '../../components/items/ApiIcon';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -212,9 +211,8 @@ export default function CategoryDetail() {
const categoryActions = useMemo(() => { const categoryActions = useMemo(() => {
return [ return [
<AdminButton model={ModelType.partcategory} pk={category.pk} />, <AdminButton model={ModelType.partcategory} pk={category.pk} />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Category Actions`} tooltip={t`Category Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
hidden: !id || !user.hasChangeRole(UserRoles.part_category), hidden: !id || !user.hasChangeRole(UserRoles.part_category),

View File

@ -15,7 +15,6 @@ import {
IconCalendarStats, IconCalendarStats,
IconClipboardList, IconClipboardList,
IconCurrencyDollar, IconCurrencyDollar,
IconDots,
IconInfoCircle, IconInfoCircle,
IconLayersLinked, IconLayersLinked,
IconList, IconList,
@ -51,7 +50,8 @@ import {
BarcodeActionDropdown, BarcodeActionDropdown,
DeleteItemAction, DeleteItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { PlaceholderPanel } from '../../components/items/Placeholder'; import { PlaceholderPanel } from '../../components/items/Placeholder';
import { StylishText } from '../../components/items/StylishText'; import { StylishText } from '../../components/items/StylishText';
@ -1030,9 +1030,8 @@ export default function PartDetail() {
} }
]} ]}
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Part Actions`} tooltip={t`Part Actions`}
icon={<IconDots />}
actions={[ actions={[
DuplicateItemAction({ DuplicateItemAction({
hidden: !user.hasAddRole(UserRoles.part), hidden: !user.hasAddRole(UserRoles.part),

View File

@ -1,7 +1,6 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Accordion, Grid, Skeleton, Stack } from '@mantine/core'; import { Accordion, Grid, Skeleton, Stack } from '@mantine/core';
import { import {
IconDots,
IconInfoCircle, IconInfoCircle,
IconList, IconList,
IconNotes, IconNotes,
@ -19,12 +18,12 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
BarcodeActionDropdown, BarcodeActionDropdown,
CancelItemAction, CancelItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction, EditItemAction,
HoldItemAction HoldItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { StylishText } from '../../components/items/StylishText'; import { StylishText } from '../../components/items/StylishText';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -408,9 +407,8 @@ export default function PurchaseOrderDetail() {
items={[order.pk]} items={[order.pk]}
enableReports enableReports
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Order Actions`} tooltip={t`Order Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
hidden: !canEdit, hidden: !canEdit,

View File

@ -1,7 +1,6 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Accordion, Grid, Skeleton, Stack } from '@mantine/core'; import { Accordion, Grid, Skeleton, Stack } from '@mantine/core';
import { import {
IconDots,
IconInfoCircle, IconInfoCircle,
IconList, IconList,
IconNotes, IconNotes,
@ -18,12 +17,12 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
BarcodeActionDropdown, BarcodeActionDropdown,
CancelItemAction, CancelItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction, EditItemAction,
HoldItemAction HoldItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { StylishText } from '../../components/items/StylishText'; import { StylishText } from '../../components/items/StylishText';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -409,9 +408,8 @@ export default function ReturnOrderDetail() {
items={[order.pk]} items={[order.pk]}
enableReports enableReports
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Order Actions`} tooltip={t`Order Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
hidden: !user.hasChangeRole(UserRoles.return_order), hidden: !user.hasChangeRole(UserRoles.return_order),

View File

@ -2,7 +2,6 @@ import { t } from '@lingui/macro';
import { Accordion, Grid, Skeleton, Stack } from '@mantine/core'; import { Accordion, Grid, Skeleton, Stack } from '@mantine/core';
import { import {
IconBookmark, IconBookmark,
IconDots,
IconInfoCircle, IconInfoCircle,
IconList, IconList,
IconNotes, IconNotes,
@ -21,12 +20,12 @@ import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails'; import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import NotesEditor from '../../components/editors/NotesEditor'; import NotesEditor from '../../components/editors/NotesEditor';
import { import {
ActionDropdown,
BarcodeActionDropdown, BarcodeActionDropdown,
CancelItemAction, CancelItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction, EditItemAction,
HoldItemAction HoldItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { StylishText } from '../../components/items/StylishText'; import { StylishText } from '../../components/items/StylishText';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -449,9 +448,8 @@ export default function SalesOrderDetail() {
items={[order.pk]} items={[order.pk]}
enableReports enableReports
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Order Actions`} tooltip={t`Order Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
hidden: !canEdit, hidden: !canEdit,

View File

@ -1,11 +1,6 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Group, Skeleton, Stack, Text } from '@mantine/core'; import { Group, Skeleton, Stack, Text } from '@mantine/core';
import { import { IconInfoCircle, IconPackages, IconSitemap } from '@tabler/icons-react';
IconDots,
IconInfoCircle,
IconPackages,
IconSitemap
} from '@tabler/icons-react';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
@ -18,7 +13,8 @@ import {
ActionDropdown, ActionDropdown,
BarcodeActionDropdown, BarcodeActionDropdown,
DeleteItemAction, DeleteItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { ApiIcon } from '../../components/items/ApiIcon'; import { ApiIcon } from '../../components/items/ApiIcon';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -331,9 +327,8 @@ export default function Stock() {
} }
]} ]}
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Location Actions`} tooltip={t`Location Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
hidden: !id || !user.hasChangeRole(UserRoles.stock_location), hidden: !id || !user.hasChangeRole(UserRoles.stock_location),

View File

@ -4,7 +4,6 @@ import {
IconBookmark, IconBookmark,
IconBoxPadding, IconBoxPadding,
IconChecklist, IconChecklist,
IconDots,
IconHistory, IconHistory,
IconInfoCircle, IconInfoCircle,
IconNotes, IconNotes,
@ -27,7 +26,8 @@ import {
BarcodeActionDropdown, BarcodeActionDropdown,
DeleteItemAction, DeleteItemAction,
DuplicateItemAction, DuplicateItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { StylishText } from '../../components/items/StylishText'; import { StylishText } from '../../components/items/StylishText';
import InstanceDetail from '../../components/nav/InstanceDetail'; import InstanceDetail from '../../components/nav/InstanceDetail';
@ -526,9 +526,8 @@ export default function StockDetail() {
} }
]} ]}
/>, />,
<ActionDropdown <OptionsActionDropdown
tooltip={t`Stock Item Actions`} tooltip={t`Stock Item Actions`}
icon={<IconDots />}
actions={[ actions={[
DuplicateItemAction({ DuplicateItemAction({
hidden: !user.hasAddRole(UserRoles.stock), hidden: !user.hasAddRole(UserRoles.stock),

View File

@ -16,7 +16,7 @@ import {
Title Title
} from '@mantine/core'; } from '@mantine/core';
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import { IconCheck, IconDots, IconRefresh } from '@tabler/icons-react'; import { IconCheck, IconRefresh } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -25,9 +25,9 @@ import { api } from '../../App';
import { AddItemButton } from '../../components/buttons/AddItemButton'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { YesNoButton } from '../../components/buttons/YesNoButton'; import { YesNoButton } from '../../components/buttons/YesNoButton';
import { import {
ActionDropdown,
DeleteItemAction, DeleteItemAction,
EditItemAction EditItemAction,
OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { InfoItem } from '../../components/items/InfoItem'; import { InfoItem } from '../../components/items/InfoItem';
import { UnavailableIndicator } from '../../components/items/UnavailableIndicator'; import { UnavailableIndicator } from '../../components/items/UnavailableIndicator';
@ -255,9 +255,8 @@ function MachineDrawer({
<Trans>Restart required</Trans> <Trans>Restart required</Trans>
</Badge> </Badge>
)} )}
<ActionDropdown <OptionsActionDropdown
tooltip={t`Machine Actions`} tooltip={t`Machine Actions`}
icon={<IconDots />}
actions={[ actions={[
EditItemAction({ EditItemAction({
tooltip: t`Edit machine`, tooltip: t`Edit machine`,