Skip to content

Commit b915673

Browse files
authored
Merge pull request #11 from dialectlabs/chore/adjust-container
feat: move disclaimer layout to ActionLayout
2 parents 83e83b3 + be4dd67 commit b915673

File tree

2 files changed

+126
-57
lines changed

2 files changed

+126
-57
lines changed

src/ui/ActionContainer.tsx

Lines changed: 19 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ import {
1717
isPostRequestError,
1818
isSignTransactionError,
1919
} from '../utils/type-guards.ts';
20-
import type { ButtonProps, StylePreset } from './ActionLayout';
21-
import { ActionLayout } from './ActionLayout';
22-
import { Snackbar } from './Snackbar.tsx';
20+
import {
21+
ActionLayout,
22+
DisclaimerType,
23+
type ButtonProps,
24+
type Disclaimer,
25+
type StylePreset,
26+
} from './ActionLayout';
2327

2428
type ExecutionStatus = 'blocked' | 'idle' | 'executing' | 'success' | 'error';
2529

@@ -404,57 +408,21 @@ export const ActionContainer = ({
404408
};
405409
};
406410

407-
const disclaimer = useMemo(() => {
408-
if (overallState === 'malicious' && executionState.status === 'blocked') {
409-
return (
410-
<Snackbar variant="error">
411-
<p>
412-
This Action or it&apos;s origin has been flagged as an unsafe
413-
action, & has been blocked. If you believe this action has been
414-
blocked in error, please{' '}
415-
<a
416-
href="https://discord.gg/saydialect"
417-
className="cursor-pointer underline"
418-
target="_blank"
419-
rel="noopener noreferrer"
420-
>
421-
submit an issue
422-
</a>
423-
.
424-
{!isPassingSecurityCheck &&
425-
' Your action provider blocks execution of this action.'}
426-
</p>
427-
{isPassingSecurityCheck && (
428-
<button
429-
className="mt-3 font-semibold transition-colors hover:text-text-error-hover motion-reduce:transition-none"
430-
onClick={() => dispatch({ type: ExecutionType.UNBLOCK })}
431-
>
432-
Ignore warning & proceed
433-
</button>
434-
)}
435-
</Snackbar>
436-
);
411+
const disclaimer: Disclaimer | null = useMemo(() => {
412+
if (overallState === 'malicious') {
413+
return {
414+
type: DisclaimerType.BLOCKED,
415+
ignorable: isPassingSecurityCheck,
416+
hidden: executionState.status !== 'blocked',
417+
onSkip: () => dispatch({ type: ExecutionType.UNBLOCK }),
418+
};
437419
}
438420

439421
if (overallState === 'unknown') {
440-
return (
441-
<Snackbar variant="warning">
442-
<p>
443-
This Action has not yet been registered. Only use it if you trust
444-
the source. This Action will not unfurl on X until it is registered.
445-
{!isPassingSecurityCheck &&
446-
' Your action provider blocks execution of this action.'}
447-
</p>
448-
<a
449-
className="mt-3 inline-block font-semibold transition-colors hover:text-text-warning-hover motion-reduce:transition-none"
450-
href="https://discord.gg/saydialect"
451-
target="_blank"
452-
rel="noopener noreferrer"
453-
>
454-
Report
455-
</a>
456-
</Snackbar>
457-
);
422+
return {
423+
type: DisclaimerType.UNKNOWN,
424+
ignorable: isPassingSecurityCheck,
425+
};
458426
}
459427

460428
return null;

src/ui/ActionLayout.tsx

Lines changed: 107 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useState, type ChangeEvent, type ReactNode } from 'react';
33
import type { ExtendedActionState } from '../api';
44
import { Badge } from './Badge.tsx';
55
import { Button } from './Button';
6+
import { Snackbar } from './Snackbar.tsx';
67
import {
78
CheckIcon,
89
ExclamationShieldIcon,
@@ -14,6 +15,23 @@ import {
1415
type ActionType = ExtendedActionState;
1516

1617
export type StylePreset = 'default' | 'x-dark' | 'x-light' | 'custom';
18+
export enum DisclaimerType {
19+
BLOCKED = 'blocked',
20+
UNKNOWN = 'unknown',
21+
}
22+
23+
export type Disclaimer =
24+
| {
25+
type: DisclaimerType.BLOCKED;
26+
ignorable: boolean;
27+
hidden: boolean;
28+
onSkip: () => void;
29+
}
30+
| {
31+
type: DisclaimerType.UNKNOWN;
32+
ignorable: boolean;
33+
};
34+
1735
const stylePresetClassMap: Record<StylePreset, string> = {
1836
default: 'dial-light',
1937
'x-dark': 'x-dark',
@@ -28,7 +46,7 @@ interface LayoutProps {
2846
success?: string | null;
2947
websiteUrl?: string | null;
3048
websiteText?: string | null;
31-
disclaimer?: ReactNode;
49+
disclaimer?: Disclaimer | null;
3250
type: ActionType;
3351
title: string;
3452
description: string;
@@ -79,6 +97,72 @@ const Linkable = ({
7997
<div className={className}>{children}</div>
8098
);
8199

100+
const DisclaimerBlock = ({
101+
type,
102+
hidden,
103+
ignorable,
104+
onSkip,
105+
}: {
106+
type: DisclaimerType;
107+
ignorable: boolean;
108+
onSkip?: () => void;
109+
hidden: boolean;
110+
}) => {
111+
if (type === DisclaimerType.BLOCKED && !hidden) {
112+
return (
113+
<Snackbar variant="error">
114+
<p>
115+
This Action or it&apos;s origin has been flagged as an unsafe action,
116+
& has been blocked. If you believe this action has been blocked in
117+
error, please{' '}
118+
<a
119+
href="https://discord.gg/saydialect"
120+
className="cursor-pointer underline"
121+
target="_blank"
122+
rel="noopener noreferrer"
123+
>
124+
submit an issue
125+
</a>
126+
.
127+
{!ignorable &&
128+
' Your action provider blocks execution of this action.'}
129+
</p>
130+
{ignorable && onSkip && (
131+
<button
132+
className="mt-3 font-semibold transition-colors hover:text-text-error-hover motion-reduce:transition-none"
133+
onClick={onSkip}
134+
>
135+
Ignore warning & proceed
136+
</button>
137+
)}
138+
</Snackbar>
139+
);
140+
}
141+
142+
if (type === DisclaimerType.UNKNOWN) {
143+
return (
144+
<Snackbar variant="warning">
145+
<p>
146+
This Action has not yet been registered. Only use it if you trust the
147+
source. This Action will not unfurl on X until it is registered.
148+
{!ignorable &&
149+
' Your action provider blocks execution of this action.'}
150+
</p>
151+
<a
152+
className="mt-3 inline-block font-semibold transition-colors hover:text-text-warning-hover motion-reduce:transition-none"
153+
href="https://discord.gg/saydialect"
154+
target="_blank"
155+
rel="noopener noreferrer"
156+
>
157+
Report
158+
</a>
159+
</Snackbar>
160+
);
161+
}
162+
163+
return null;
164+
};
165+
82166
export const ActionLayout = ({
83167
stylePreset = 'default',
84168
title,
@@ -119,13 +203,13 @@ export const ActionLayout = ({
119203
rel="noopener noreferrer"
120204
>
121205
<LinkIcon className="mr-2 text-icon-primary transition-colors group-hover:text-icon-primary-hover motion-reduce:transition-none" />
122-
<span className="text-text-link transition-colors group-hover:text-text-link-hover group-hover:underline motion-reduce:transition-none">
206+
<span className="text-text-link group-hover:text-text-link-hover transition-colors group-hover:underline motion-reduce:transition-none">
123207
{websiteText ?? websiteUrl}
124208
</span>
125209
</a>
126210
)}
127211
{websiteText && !websiteUrl && (
128-
<span className="inline-flex items-center truncate text-subtext text-text-link">
212+
<span className="text-text-link inline-flex items-center truncate text-subtext">
129213
{websiteText}
130214
</span>
131215
)}
@@ -163,7 +247,24 @@ export const ActionLayout = ({
163247
<span className="mb-4 whitespace-pre-wrap text-subtext text-text-secondary">
164248
{description}
165249
</span>
166-
{disclaimer && <div className="mb-4">{disclaimer}</div>}
250+
{disclaimer && (
251+
<div className="mb-4">
252+
<DisclaimerBlock
253+
type={disclaimer.type}
254+
ignorable={disclaimer.ignorable}
255+
hidden={
256+
disclaimer.type === DisclaimerType.BLOCKED
257+
? disclaimer.hidden
258+
: false
259+
}
260+
onSkip={
261+
disclaimer.type === DisclaimerType.BLOCKED
262+
? disclaimer.onSkip
263+
: undefined
264+
}
265+
/>
266+
</div>
267+
)}
167268
<ActionContent form={form} inputs={inputs} buttons={buttons} />
168269
{success && (
169270
<span className="mt-4 flex justify-center text-subtext text-text-success">
@@ -259,7 +360,7 @@ const ActionInput = ({
259360
return (
260361
<div
261362
className={clsx(
262-
'flex items-center gap-2 rounded-input border border-input-stroke transition-colors focus-within:border-input-stroke-selected motion-reduce:transition-none',
363+
'border-input-stroke focus-within:border-input-stroke-selected flex items-center gap-2 rounded-input border transition-colors motion-reduce:transition-none',
263364
{
264365
'hover:border-input-stroke-hover hover:focus-within:border-input-stroke-selected':
265366
!disabled,
@@ -271,7 +372,7 @@ const ActionInput = ({
271372
value={value}
272373
disabled={disabled}
273374
onChange={extendedChange}
274-
className="my-3 ml-4 flex-1 truncate bg-input-bg text-text-input outline-none placeholder:text-text-input-placeholder disabled:text-text-input-disabled"
375+
className="bg-input-bg text-text-input placeholder:text-text-input-placeholder disabled:text-text-input-disabled my-3 ml-4 flex-1 truncate outline-none"
275376
/>
276377
{button && (
277378
<div className="my-2 mr-2">

0 commit comments

Comments
 (0)