1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

[FLASK] Expanded Snap authorship (#18775)

This commit is contained in:
Guillaume Roux 2023-04-25 19:20:37 +02:00 committed by GitHub
parent a4a5b28f2e
commit 6126c156ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 396 additions and 197 deletions

View File

@ -1066,6 +1066,10 @@
"description": {
"message": "Description"
},
"descriptionFromSnap": {
"message": "Description from $1",
"description": "$1 represents the name of the snap"
},
"desktopConnectionCriticalErrorDescription": {
"message": "This error could be intermittent, so try restarting the extension or disable MetaMask Desktop."
},
@ -1331,10 +1335,7 @@
"message": "Enable smart transactions"
},
"enableSnap": {
"message": "Enable snap"
},
"enableSnapDescription": {
"message": "Your installed snap will only have access to its permissions and run if its enabled."
"message": "Enable"
},
"enableToken": {
"message": "enable $1",
@ -1851,6 +1852,13 @@
"install": {
"message": "Install"
},
"installOrigin": {
"message": "Install origin"
},
"installedOn": {
"message": "Installed on $1",
"description": "$1 is the date when the snap has been installed"
},
"institutionalFeatures": {
"message": "Institutional Features"
},
@ -2192,6 +2200,9 @@
"mmiAuthenticate": {
"message": "The page at $1 would like to authorise the following projects compliance settings in MetaMask Institutional"
},
"more": {
"message": "more"
},
"moreComingSoon": {
"message": "More coming soon..."
},
@ -3576,6 +3587,10 @@
"settingsSearchMatchingNotFound": {
"message": "No matching results found."
},
"shortVersion": {
"message": "v$1",
"description": "$1 is the version number to show"
},
"show": {
"message": "Show"
},
@ -4510,7 +4525,6 @@
"transactionFailed": {
"message": "Transaction Failed"
},
"transactionFee": {
"message": "Transaction fee"
},
@ -4737,6 +4751,9 @@
"message": "Verify this token on $1 and make sure this is the token you want to trade.",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"version": {
"message": "Version"
},
"view": {
"message": "View"
},
@ -4870,10 +4887,6 @@
"message": "You've added all the popular networks. You can discover more networks $1 Or you can $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youInstalled": {
"message": "You installed",
"description": "Part of version description for installed snap"
},
"youNeedToAllowCameraAccess": {
"message": "You need to allow camera access to use this feature."
},

View File

@ -43,6 +43,7 @@
@import 'snaps/snap-settings-card/index';
@import 'snaps/update-snap-permission-list/index';
@import 'snaps/copyable/index';
@import 'snaps/snap-version/index';
@import 'gas-details-item/index';
@import 'gas-details-item/gas-details-item-title/index';
@import 'gas-timing/index';

View File

@ -2,30 +2,42 @@ import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { getSnapPrefix } from '@metamask/snaps-utils';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import Box from '../../../ui/box';
import {
BackgroundColor,
TextColor,
IconColor,
FLEX_DIRECTION,
TextVariant,
BorderColor,
AlignItems,
DISPLAY,
BorderRadius,
BLOCK_SIZES,
JustifyContent,
BorderStyle,
Color,
BorderRadius,
} from '../../../../helpers/constants/design-system';
import {
formatDate,
getSnapName,
removeSnapIdPrefix,
} from '../../../../helpers/utils/util';
import { ButtonIcon, IconName, Text } from '../../../component-library';
import { Text, ButtonLink } from '../../../component-library';
import { getTargetSubjectMetadata } from '../../../../selectors';
import SnapAvatar from '../snap-avatar';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import Tooltip from '../../../ui/tooltip/tooltip';
import ToggleButton from '../../../ui/toggle-button';
import { disableSnap, enableSnap } from '../../../../store/actions';
import { useOriginMetadata } from '../../../../hooks/useOriginMetadata';
import SnapVersion from '../snap-version/snap-version';
const SnapAuthorship = ({ snapId, className, expanded = false, snap }) => {
const t = useI18nContext();
const dispatch = useDispatch();
const SnapAuthorship = ({ snapId, className }) => {
// We're using optional chaining with snapId, because with the current implementation
// of snap update in the snap controller, we do not have reference to snapId when an
// update request is rejected because the reference comes from the request itself and not subject metadata
@ -43,48 +55,127 @@ const SnapAuthorship = ({ snapId, className }) => {
const friendlyName = snapId && getSnapName(snapId, subjectMetadata);
// Expanded data
const versionHistory = snap?.versionHistory ?? [];
const installInfo = versionHistory.length
? versionHistory[versionHistory.length - 1]
: undefined;
const installOrigin = useOriginMetadata(installInfo?.origin);
const onToggle = () => {
if (snap?.enabled) {
dispatch(disableSnap(snap?.id));
} else {
dispatch(enableSnap(snap?.id));
}
};
return (
<Box
className={classnames('snaps-authorship', className)}
backgroundColor={BackgroundColor.backgroundDefault}
borderColor={BorderColor.borderDefault}
borderWidth={1}
alignItems={AlignItems.center}
paddingLeft={2}
paddingTop={2}
paddingBottom={2}
paddingRight={4}
borderRadius={BorderRadius.pill}
display={DISPLAY.FLEX}
width={BLOCK_SIZES.FULL}
borderRadius={expanded ? BorderRadius.LG : BorderRadius.pill}
>
<Box>
<SnapAvatar snapId={snapId} />
</Box>
<Box
marginLeft={4}
marginRight={2}
alignItems={AlignItems.center}
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.COLUMN}
style={{ overflow: 'hidden' }}
width={BLOCK_SIZES.FULL}
paddingLeft={expanded ? 4 : 2}
paddingRight={expanded ? 4 : 2}
paddingTop={expanded ? 3 : 1}
paddingBottom={expanded ? 3 : 1}
>
<Text ellipsis>{friendlyName}</Text>
<Text
ellipsis
variant={TextVariant.bodySm}
color={TextColor.textAlternative}
<Box>
<SnapAvatar snapId={snapId} />
</Box>
<Box
marginLeft={2}
marginRight={expanded ? 0 : 2}
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.COLUMN}
style={{ overflow: 'hidden' }}
>
{packageName}
</Text>
<Text ellipsis>{friendlyName}</Text>
<Text
ellipsis
variant={TextVariant.bodySm}
color={TextColor.textAlternative}
>
{packageName}
</Text>
</Box>
{!expanded && (
<Box marginLeft="auto">
<SnapVersion version={subjectMetadata?.version} url={url} />
</Box>
)}
</Box>
<ButtonIcon
rel="noopener noreferrer"
target="_blank"
href={url}
iconName={IconName.Export}
color={IconColor.infoDefault}
style={{ marginLeft: 'auto' }}
/>
{expanded && (
<Box flexDirection={FLEX_DIRECTION.COLUMN} width={BLOCK_SIZES.FULL}>
<Box
flexDirection={FLEX_DIRECTION.ROW}
justifyContent={JustifyContent.spaceBetween}
paddingLeft={4}
paddingTop={4}
paddingBottom={4}
borderColor={BorderColor.borderDefault}
width={BLOCK_SIZES.FULL}
style={{
borderLeft: BorderStyle.none,
borderRight: BorderStyle.none,
}}
>
<Text variant={TextVariant.bodyMdBold}>{t('enableSnap')}</Text>
<Box style={{ maxWidth: '52px' }}>
<Tooltip interactive position="left" html={t('snapsToggle')}>
<ToggleButton value={snap?.enabled} onToggle={onToggle} />
</Tooltip>
</Box>
</Box>
<Box
flexDirection={FLEX_DIRECTION.COLUMN}
padding={4}
width={BLOCK_SIZES.FULL}
>
{installOrigin && installInfo && (
<Box
flexDirection={FLEX_DIRECTION.ROW}
justifyContent={JustifyContent.spaceBetween}
width={BLOCK_SIZES.FULL}
>
<Text variant={TextVariant.bodyMdBold}>
{t('installOrigin')}
</Text>
<Box
flexDirection={FLEX_DIRECTION.COLUMN}
alignItems={AlignItems.flexEnd}
>
<ButtonLink href={installOrigin.origin} target="_blank">
{installOrigin.host}
</ButtonLink>
<Text color={Color.textMuted}>
{t('installedOn', [
formatDate(installInfo.date, 'dd MMM yyyy'),
])}
</Text>
</Box>
</Box>
)}
<Box
flexDirection={FLEX_DIRECTION.ROW}
justifyContent={JustifyContent.spaceBetween}
alignItems={AlignItems.center}
marginTop={4}
>
<Text variant={TextVariant.bodyMdBold}>{t('version')}</Text>
<SnapVersion version={snap?.version} url={url} />
</Box>
</Box>
</Box>
)}
</Box>
);
};
@ -98,6 +189,14 @@ SnapAuthorship.propTypes = {
* The className of the SnapAuthorship
*/
className: PropTypes.string,
/**
* If the authorship component should be expanded
*/
expanded: PropTypes.bool,
/**
* The snap object. Can be undefined if the component is not expanded
*/
snap: PropTypes.object,
};
export default SnapAuthorship;

View File

@ -50,10 +50,10 @@ const SnapAvatar = ({ snapId, className }) => {
position={BadgeWrapperPosition.bottomRight}
>
{iconUrl ? (
<AvatarFavicon size={Size.LG} src={iconUrl} name={friendlyName} />
<AvatarFavicon size={Size.MD} src={iconUrl} name={friendlyName} />
) : (
<AvatarBase
size={Size.LG}
size={Size.MD}
display={DISPLAY.FLEX}
alignItems={AlignItems.center}
justifyContent={JustifyContent.center}

View File

@ -0,0 +1 @@
export { default } from './snap-version';

View File

@ -0,0 +1,15 @@
.snap-version {
&:hover {
opacity: 1;
}
&__wrapper {
&:hover {
background-color: var(--color-info-muted);
& * {
color: var(--color-info-default);
}
}
}
}

View File

@ -0,0 +1,72 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
AlignItems,
BackgroundColor,
BorderRadius,
Color,
FLEX_DIRECTION,
TextVariant,
} from '../../../../helpers/constants/design-system';
import Box from '../../../ui/box';
import {
BUTTON_TYPES,
Button,
Icon,
IconName,
IconSize,
Text,
} from '../../../component-library';
import Preloader from '../../../ui/icon/preloader/preloader-icon.component';
import { useI18nContext } from '../../../../hooks/useI18nContext';
const SnapVersion = ({ version, url }) => {
const t = useI18nContext();
return (
<Button
type={BUTTON_TYPES.LINK}
href={url}
target="_blank"
className="snap-version"
>
<Box
className="snap-version__wrapper"
flexDirection={FLEX_DIRECTION.ROW}
alignItems={AlignItems.center}
backgroundColor={BackgroundColor.backgroundAlternative}
borderRadius={BorderRadius.pill}
paddingTop={1}
paddingBottom={1}
paddingLeft={2}
paddingRight={2}
>
{version ? (
<Text color={Color.textAlternative} variant={TextVariant.bodyMd}>
{t('shortVersion', [version])}
</Text>
) : (
<Preloader size={18} />
)}
<Icon
name={IconName.Export}
color={Color.textAlternative}
size={IconSize.Sm}
marginLeft={1}
/>
</Box>
</Button>
);
};
SnapVersion.propTypes = {
/**
* The version of the snap
*/
version: PropTypes.string,
/**
* The url to the snap package
*/
url: PropTypes.string,
};
export default SnapVersion;

View File

@ -0,0 +1,20 @@
import React from 'react';
import SnapVersion from '.';
export default {
title: 'Components/App/Snaps/SnapVersion',
component: SnapVersion,
};
export const DefaultStory = (args) => <SnapVersion {...args} />;
DefaultStory.args = {
version: '1.4.2',
url: 'https://www.npmjs.com/package/@metamask/test-snap-error',
};
export const LoadingStory = (args) => <SnapVersion {...args} />;
LoadingStory.args = {
version: undefined,
url: 'https://www.npmjs.com/package/@metamask/test-snap-error',
};

View File

@ -0,0 +1,27 @@
import * as React from 'react';
import { renderWithLocalization } from '../../../../../test/lib/render-helpers';
import SnapVersion from './snap-version';
describe('SnapVersion', () => {
const args = {
version: '1.4.2',
url: 'https://www.npmjs.com/package/@metamask/test-snap-error',
};
it('should render the SnapVersion without crashing and display a version', () => {
const { getByText, container } = renderWithLocalization(
<SnapVersion {...args} />,
);
expect(getByText(`v${args.version}`)).toBeDefined();
expect(container.firstChild).toHaveAttribute('href', args.url);
});
it('should have a loading state if no version is passed', () => {
args.version = undefined;
const { container } = renderWithLocalization(<SnapVersion {...args} />);
expect(container.getElementsByClassName('preloader__icon')).toHaveLength(1);
expect(container.firstChild).toHaveAttribute('href', args.url);
});
});

View File

@ -3,6 +3,7 @@ export enum DelineatorType {
// eslint-disable-next-line @typescript-eslint/no-shadow
Error = 'error',
Insights = 'insights',
Description = 'description',
}
export const getDelineatorTitle = (type: DelineatorType) => {
@ -11,6 +12,8 @@ export const getDelineatorTitle = (type: DelineatorType) => {
return 'errorWithSnap';
case DelineatorType.Insights:
return 'insightsFromSnap';
case DelineatorType.Description:
return 'descriptionFromSnap';
default:
return 'contentFromSnap';
}

View File

@ -1,7 +1,7 @@
.snap-install {
box-shadow: none;
.headers {
.content {
flex: 1;
.loader-container {

View File

@ -84,13 +84,13 @@ export default function SnapInstall({
flexDirection={FLEX_DIRECTION.COLUMN}
>
<Box
className="headers"
className="header"
alignItems={AlignItems.center}
paddingLeft={4}
paddingRight={4}
flexDirection={FLEX_DIRECTION.COLUMN}
>
<Box paddingLeft={4} paddingRight={4}>
<SnapAuthorship snapId={targetSubjectMetadata.origin} />
</Box>
<SnapAuthorship snapId={targetSubjectMetadata.origin} />
{!hasError && (
<Text
variant={TextVariant.headingLg}
@ -100,6 +100,8 @@ export default function SnapInstall({
{t('snapInstall')}
</Text>
)}
</Box>
<Box className="content">
{isLoading && (
<Box
className="loader-container"
@ -116,7 +118,7 @@ export default function SnapInstall({
{hasPermissions && (
<>
<Text
className="headers__permission-description"
className="content__permission-description"
paddingBottom={4}
paddingLeft={4}
paddingRight={4}

View File

@ -1,7 +1,7 @@
.snap-update {
box-shadow: none;
.headers {
.content {
flex: 1;
.loader-container {

View File

@ -90,7 +90,7 @@ export default function SnapUpdate({
flexDirection={FLEX_DIRECTION.COLUMN}
>
<Box
className="headers"
className="header"
paddingLeft={4}
paddingRight={4}
alignItems={AlignItems.center}
@ -106,6 +106,8 @@ export default function SnapUpdate({
{t('snapUpdate')}
</Text>
)}
</Box>
<Box className="content">
{isLoading && (
<Box
className="loader-container"
@ -122,8 +124,10 @@ export default function SnapUpdate({
{hasPermissions && (
<>
<Text
className="headers__permission-description"
className="content__permission-description"
paddingBottom={4}
paddingLeft={4}
paddingRight={4}
textAlign={TEXT_ALIGN.CENTER}
>
{t('snapUpdateRequestsPermission', [

View File

@ -1,19 +1,36 @@
.view-snap {
max-width: 475px;
&__version_info {
&__version-number {
font-weight: bold;
&__description {
&__wrapper {
position: relative;
overflow: hidden;
max-height: 5.5rem;
@include screen-md-min {
max-height: 6rem;
}
&.open {
max-height: none;
}
}
&__link {
vertical-align: top;
&__more-button {
position: absolute;
bottom: 0;
right: 0;
width: unset;
padding: 0;
padding-left: 32px;
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--color-background-default) 33%);
}
}
&__enable {
&__tooltip_wrapper {
max-width: 52px;
&__permissions {
.permission-cell {
margin: 0;
}
}

View File

@ -1,28 +1,26 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import {
SnapCaveatType,
WALLET_SNAP_PERMISSION_KEY,
} from '@metamask/rpc-methods';
import { getSnapPrefix } from '@metamask/snaps-utils';
import classnames from 'classnames';
import Button from '../../../../components/ui/button';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
Size,
Color,
FLEX_WRAP,
TextColor,
TextVariant,
} from '../../../../helpers/constants/design-system';
import SnapAuthorship from '../../../../components/app/snaps/snap-authorship';
import Box from '../../../../components/ui/box';
import SnapRemoveWarning from '../../../../components/app/snaps/snap-remove-warning';
import ToggleButton from '../../../../components/ui/toggle-button';
import ConnectedSitesList from '../../../../components/app/connected-sites-list';
import Tooltip from '../../../../components/ui/tooltip';
import { SNAPS_LIST_ROUTE } from '../../../../helpers/constants/routes';
import {
disableSnap,
enableSnap,
removeSnap,
removePermissionsFor,
updateCaveat,
@ -34,18 +32,17 @@ import {
getPermissionSubjects,
getTargetSubjectMetadata,
} from '../../../../selectors';
import {
formatDate,
getSnapName,
removeSnapIdPrefix,
} from '../../../../helpers/utils/util';
import { ButtonLink, Text } from '../../../../components/component-library';
import { getSnapName } from '../../../../helpers/utils/util';
import { Text, BUTTON_TYPES } from '../../../../components/component-library';
import SnapPermissionsList from '../../../../components/app/snaps/snap-permissions-list';
import { SnapDelineator } from '../../../../components/app/snaps/snap-delineator';
import { DelineatorType } from '../../../../helpers/constants/flask';
function ViewSnap() {
const t = useI18nContext();
const history = useHistory();
const location = useLocation();
const descriptionRef = useRef(null);
const { pathname } = location;
// The snap ID is in URI-encoded form in the last path segment of the URL.
const decodedSnapId = decodeURIComponent(pathname.match(/[^/]+$/u)[0]);
@ -55,6 +52,8 @@ function ViewSnap() {
.find((snapState) => snapState.id === decodedSnapId);
const [isShowingRemoveWarning, setIsShowingRemoveWarning] = useState(false);
const [isDescriptionOpen, setIsDescriptionOpen] = useState(false);
const [isOverflowing, setIsOverflowing] = useState(false);
useEffect(() => {
if (!snap) {
@ -62,6 +61,14 @@ function ViewSnap() {
}
}, [history, snap]);
useEffect(() => {
setIsOverflowing(
descriptionRef.current &&
descriptionRef.current.offsetHeight <
descriptionRef.current.scrollHeight,
);
}, [descriptionRef]);
const connectedSubjects = useSelector((state) =>
getSubjectsWithSnapPermission(state, snap?.id),
);
@ -74,14 +81,6 @@ function ViewSnap() {
);
const dispatch = useDispatch();
const onToggle = () => {
if (snap.enabled) {
dispatch(disableSnap(snap.id));
} else {
dispatch(enableSnap(snap.id));
}
};
const onDisconnect = (connectedOrigin, snapId) => {
const caveatValue =
subjects[connectedOrigin].permissions[WALLET_SNAP_PERMISSION_KEY]
@ -110,121 +109,51 @@ function ViewSnap() {
return null;
}
const versionHistory = snap.versionHistory ?? [];
const installInfo = versionHistory.length
? versionHistory[versionHistory.length - 1]
: undefined;
const packageName = snap.id && removeSnapIdPrefix(snap.id);
const snapPrefix = snap.id && getSnapPrefix(snap.id);
const isNPM = snapPrefix === 'npm:';
const url = isNPM
? `https://www.npmjs.com/package/${packageName}`
: packageName;
const snapName = getSnapName(snap.id, targetSubjectMetadata);
const shouldDisplayMoreButton = isOverflowing && !isDescriptionOpen;
const handleMoreClick = () => {
setIsDescriptionOpen(true);
};
return (
<Box
className="view-snap"
paddingBottom={8}
paddingLeft={3}
paddingRight={3}
paddingBottom={[4, 8]}
paddingTop={[4, 8]}
paddingLeft={4}
paddingRight={4}
>
<Box
className="view-snap__header"
paddingTop={8}
marginLeft={4}
marginRight={4}
>
<SnapAuthorship snapId={snap.id} />
</Box>
<Box
className="view-snap__description"
marginTop={4}
marginLeft={4}
marginRight={4}
>
<Text variant={TextVariant.bodyMd} color={TextColor.textDefault}>
{snap.manifest.description}
</Text>
</Box>
<Box
className="view-snap__version_info"
marginTop={2}
marginLeft={4}
marginRight={4}
>
<Text variant={TextVariant.bodyMd} color={TextColor.textDefault}>
{`${t('youInstalled')} `}
<span className="view-snap__version_info__version-number">
v{snap.version}
</span>
{` ${t('ofTextNofM')} `}
<ButtonLink
size={Size.auto}
href={url}
target="_blank"
className="view-snap__version_info__link"
<SnapAuthorship snapId={snap.id} snap={snap} expanded />
<Box className="view-snap__description" marginTop={[4, 7]}>
<SnapDelineator type={DelineatorType.Description} snapName={snapName}>
<Box
className={classnames('view-snap__description__wrapper', {
open: isDescriptionOpen,
})}
ref={descriptionRef}
>
{packageName}
</ButtonLink>
{installInfo && ` ${t('from').toLowerCase()} `}
{installInfo && (
<ButtonLink
size={Size.auto}
href={installInfo.origin}
target="_blank"
className="view-snap__version_info__link"
>
{installInfo.origin}
</ButtonLink>
)}
{installInfo &&
` ${t('on').toLowerCase()} ${formatDate(
installInfo.date,
'dd MMM yyyy',
)}`}
.
</Text>
</Box>
<Box
className="view-snap__enable"
marginTop={12}
marginLeft={4}
marginRight={4}
>
<Text variant={TextVariant.bodyLgMedium}>{t('enableSnap')}</Text>
<Text
variant={TextVariant.bodyMd}
color={TextColor.textDefault}
marginBottom={4}
>
{t('enableSnapDescription')}
</Text>
<Box className="view-snap__enable__tooltip_wrapper">
<Tooltip interactive position="left" html={t('snapsToggle')}>
<ToggleButton
value={snap.enabled}
onToggle={onToggle}
className="view-snap__toggle-button"
/>
</Tooltip>
</Box>
<Text>{snap?.manifest.description}</Text>
{shouldDisplayMoreButton && (
<Button
className="view-snap__description__more-button"
type={BUTTON_TYPES.LINK}
onClick={handleMoreClick}
>
<Text color={Color.infoDefault}>{t('more')}</Text>
</Button>
)}
</Box>
</SnapDelineator>
</Box>
<Box className="view-snap__permissions" marginTop={12}>
<Text variant={TextVariant.bodyLgMedium} marginLeft={4} marginRight={4}>
{t('permissions')}
</Text>
<Text variant={TextVariant.bodyLgMedium}>{t('permissions')}</Text>
<SnapPermissionsList
permissions={permissions ?? {}}
targetSubjectMetadata={targetSubjectMetadata}
/>
</Box>
<Box
className="view-snap__connected-sites"
marginTop={12}
marginLeft={4}
marginRight={4}
>
<Box className="view-snap__connected-sites" marginTop={12}>
<Text variant={TextVariant.bodyLgMedium} marginBottom={4}>
{t('connectedSites')}
</Text>
@ -235,12 +164,7 @@ function ViewSnap() {
}}
/>
</Box>
<Box
className="view-snap__remove"
marginTop={12}
marginLeft={4}
marginRight={4}
>
<Box className="view-snap__remove" marginTop={12}>
<Text variant={TextVariant.bodyLgMedium} color={TextColor.textDefault}>
{t('removeSnap')}
</Text>
@ -253,7 +177,13 @@ function ViewSnap() {
type="danger"
onClick={() => setIsShowingRemoveWarning(true)}
>
<Text variant={TextVariant.bodyMd} color={TextColor.errorDefault}>
<Text
variant={TextVariant.bodyMd}
color={TextColor.errorDefault}
flexWrap={FLEX_WRAP.NO_WRAP}
ellipsis
style={{ overflow: 'hidden' }}
>
{`${t('remove')} ${snapName}`}
</Text>
</Button>

View File

@ -48,12 +48,7 @@ describe('ViewSnap', () => {
// Snap version info
expect(getByText('v5.1.2')).toBeDefined();
// Enable Snap
expect(getByText('Enable snap')).toBeDefined();
expect(
getByText(
'Your installed snap will only have access to its permissions and run if its enabled.',
),
).toBeDefined();
expect(getByText('Enable')).toBeDefined();
expect(container.getElementsByClassName('toggle-button')?.length).toBe(1);
// Permissions
expect(getByText('Permissions')).toBeDefined();