Skip to content

Commit

Permalink
Run the tests on all branches and PRs
Browse files Browse the repository at this point in the history
  • Loading branch information
martincik committed Jul 10, 2024
1 parent de74db4 commit 66ebcd6
Show file tree
Hide file tree
Showing 27 changed files with 1,042 additions and 560 deletions.
14 changes: 3 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build-ci:
runs-on: ubuntu-latest
Expand All @@ -23,6 +15,6 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- run: yarn install --immutable --immutable-cache --check-cache
- run: yarn run lint
- run: yarn run build-staging-release
- run: yarn run test
- run: yarn lint
- run: yarn build-staging-release
- run: yarn test
11 changes: 8 additions & 3 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { Config } from 'jest';
import type { Config } from '@jest/types';

const config: Config = {
verbose: true,
const config: Config.InitialOptions = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
globals: {
'ts-jest': {
tsconfig: './tsconfig.json',
},
},
};

export default config;
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dev": "NODE_ENV=development PORT=3000 webpack serve --env TARGET_ENV=development",
"lint": "tslint --project tsconfig.json ./src/**/*.tsx ./src/**/*.ts ./src/**/*.js",
"lint-fix": "tslint --project tsconfig.json ./src/**/*.tsx ./src/**/*.ts ./src/**/*.js --fix",
"test": "jest",
"test": "tsc && jest",
"stats": "NODE_ENV=production webpack --env TARGET_ENV=staging --profile --json > stats.json",
"knip": "knip"
},
Expand All @@ -28,9 +28,10 @@
"@babel/preset-typescript": "^7.8.3",
"@babel/runtime": "^7.19.4",
"@statoscope/webpack-plugin": "^5.24.0",
"@tsconfig/recommended": "^1.0.1",
"@tsconfig/recommended": "^1.0.7",
"@types/bn.js": "^5.1.1",
"@types/jest": "^25.2.1",
"@types/jest": "^29.5.12",
"@types/react": "^18.3.3",
"@types/react-slider": "^1.3.1",
"autoprefixer": "^10.4.19",
"babel-loader": "^8.0.6",
Expand All @@ -45,7 +46,7 @@
"dotenv-webpack": "^8.0.1",
"glob": "^9.3.2",
"inspectpack": "^4.7.1",
"jest": "^29.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.2.1",
"knip": "^0.9.0",
"mini-css-extract-plugin": "^2.7.5",
Expand All @@ -58,9 +59,10 @@
"style-loader": "^1.1.3",
"svg-url-loader": "^8.0.0",
"tailwindcss": "^3.4.4",
"ts-jest": "^29.2.1",
"ts-node": "^10.9.1",
"tslint": "^5.20.1",
"typescript": "^4.6.2",
"typescript": "^5",
"webpack": "^5",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
Expand All @@ -70,9 +72,9 @@
"@solana/wallet-adapter-react": "^0.15.35",
"@solana/wallet-adapter-react-ui": "^0.9.35",
"@solana/web3.js": "^1.66.1",
"@supercharge/promise-pool": "^3.2.0",
"@tiplink/wallet-adapter": "^2.1.16",
"@tiplink/wallet-adapter-react-ui": "^0.1.11",
"@supercharge/promise-pool": "^3.2.0",
"bn.js": "^5.2.1",
"borsh": "^0.7.0",
"clsx": "^1.2.1",
Expand Down
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { h } from "preact";
import React from 'react';
// @ts-ignore
import React, { h } from "preact";
import { useMemo } from "preact/hooks";

import {
Expand Down
4 changes: 2 additions & 2 deletions src/components/dialect/ui/ActionContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { h } from 'preact';
import * as React from 'preact';
// @ts-ignore
import React, { h } from 'preact';
import { useEffect, useMemo, useReducer, useState, useContext } from 'preact/compat';
import { Buffer } from 'buffer';
import { ActionLayout, ButtonProps } from './ActionLayout';
Expand Down
213 changes: 174 additions & 39 deletions src/components/dialect/ui/ActionLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { h, Fragment, ComponentChildren } from 'preact';
import * as React from 'preact';
import * as React from 'react';
import { h, Fragment, ComponentChildren, ComponentChild } from 'preact';

import { Button } from './Button';
import {
Expand All @@ -9,12 +9,18 @@ import {
LinkIcon,
SpinnerDots,
} from './icons';
import { ReactNode, useState } from 'react';
import clsx from 'clsx';
import { useState } from 'preact/hooks';
import { Badge } from '../ui/Badge';
import { ExtendedActionState } from '../api/ActionsRegistry';

type ActionType = ExtendedActionState;

export interface FormProps {
inputs: Array<Omit<InputProps, 'button'>>;
button: ButtonProps;
}

interface LayoutProps {
image?: string;
error?: string | null;
Expand All @@ -27,6 +33,7 @@ interface LayoutProps {
description: string;
buttons?: ButtonProps[];
inputs?: InputProps[];
form?: FormProps;
}

export interface ButtonProps {
Expand All @@ -42,15 +49,16 @@ export interface InputProps {
placeholder?: string;
name: string;
disabled: boolean;
button: ButtonProps;
required?: boolean;
button?: ButtonProps;
}

const Linkable = ({
url,
children,
}: {
url?: string | null;
children: ReactNode | ReactNode[];
children: ComponentChildren | ComponentChild;
}) =>
url ? (
<a href={url} target="_blank" rel="noopener noreferrer">
Expand All @@ -60,64 +68,191 @@ const Linkable = ({
<Fragment>{children}</Fragment>
);

const ActionContent = ({
form,
inputs,
buttons,
}: Pick<LayoutProps, 'form' | 'buttons' | 'inputs'>) => {
if (form) {
return <ActionForm form={form} />;
}

return (
<div className="flex flex-col gap-3">
{buttons && buttons.length > 0 && (
<div className="flex flex-wrap items-center gap-2">
{buttons?.map((it, index) => (
<div key={index} className="flex-auto">
<ActionButton {...it} />
</div>
))}
</div>
)}
{inputs?.map((input) => <ActionInput key={input.name} {...input} />)}
</div>
);
};

const ActionForm = ({ form }: Required<Pick<LayoutProps, 'form'>>) => {
const [values, setValues] = useState(
Object.fromEntries(form.inputs.map((i) => [i.name, ''])),
);

const onChange = (name: string, value: string) => {
setValues((prev) => ({ ...prev, [name]: value }));
};

const disabled = form.inputs.some((i) => i.required && values[i.name] === '');

return (
<div className="flex flex-col gap-3">
{form.inputs.map((input) => (
<ActionInput
key={input.name}
{...input}
onChange={(v) => onChange(input.name, v)}
/>
))}
<ActionButton
{...form.button}
onClick={() => form.button.onClick(values)}
disabled={form.button.disabled || disabled}
/>
</div>
);
};

export const ActionLayout = ({
title,
description,
image,
websiteUrl,
websiteText,
type,
disclaimer,
buttons,
inputs,
form,
error,
success,
}: LayoutProps) => {
return (
<div>
<div className="flex flex-col gap-2">
{buttons && buttons.length > 0 && (
<div className="flex flex-wrap items-center gap-2">
{buttons?.map((it, index) => (
<div key={index} className="flex-auto">
<ActionButton {...it} />
</div>
))}
</div>
)}
{inputs?.map((input) => <ActionInput key={input.name} {...input} />)}
</div>
{success && (
<span className="mt-4 flex justify-center text-subtext text-accent-success">
{success}
</span>
<div className="w-full max-w-[448px] overflow-hidden rounded-2xl bg-primary p-4 shadow-action">
{image && (
<Linkable url={websiteUrl}>
<img
className={clsx('w-full object-cover object-left', {
'aspect-square': !form,
'aspect-[2/1] rounded-xl': form,
})}
src={image}
alt="action-image"
/>
</Linkable>
)}
{error && !success && (
<span className="mt-4 flex justify-center text-subtext text-accent-error">
{error}
<div className="mt-4 flex flex-col">
<div className="mb-2 flex items-center gap-2">
{websiteUrl && (
<div
// href={websiteUrl}
// target="_blank"
className="inline-flex items-center truncate text-subtext text-quaternary transition-colors motion-reduce:transition-none"
rel="noopener noreferrer"
>
<LinkIcon className="mr-2" />
{websiteText ?? websiteUrl}
</div>
)}
{websiteText && !websiteUrl && (
<span className="inline-flex items-center truncate text-subtext text-quaternary">
{websiteText}
</span>
)}
<a
href="https://docs.dialect.to/documentation/actions/security"
target="_blank"
rel="noopener noreferrer"
className="flex items-center"
>
{type === 'malicious' && (
<Badge
variant="error"
icon={<ExclamationShieldIcon width={13} height={13} />}
>
Blocked
</Badge>
)}
{type === 'trusted' && (
<Badge
variant="default"
icon={<InfoShieldIcon width={13} height={13} />}
/>
)}
{type === 'unknown' && (
<Badge
variant="warning"
icon={<InfoShieldIcon width={13} height={13} />}
/>
)}
</a>
</div>
<span className="mb-0.5 text-text font-semibold text-primary">
{title}
</span>
)}
<span className="mb-4 text-subtext text-secondary">{description}</span>
{disclaimer && <div className="mb-4">{disclaimer}</div>}
<ActionContent form={form} inputs={inputs} buttons={buttons} />
{success && (
<span className="mt-4 flex justify-center text-subtext text-accent-success">
{success}
</span>
)}
{error && !success && (
<span className="mt-4 flex justify-center text-subtext text-accent-error">
{error}
</span>
)}
</div>
</div>
);
};

export const ActionInput = ({
const ActionInput = ({
placeholder,
name,
button,
disabled,
}: InputProps) => {
onChange: extOnChange,
required,
}: InputProps & { onChange?: (value: string) => void }) => {
const [value, onChange] = useState('');

const extendedChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.currentTarget.value);
extOnChange?.(e.currentTarget.value);
};

const placeholderWithRequired =
(placeholder || 'Type here...') + (required ? '*' : '');

return (
<div className="flex items-center gap-2 rounded-lg border border-input-primary transition-colors focus-within:border-input-checked motion-reduce:transition-none">
<input
placeholder={placeholder || 'Type here...'}
placeholder={placeholderWithRequired}
value={value}
disabled={disabled}
onChange={(e) => onChange(e.target.value)}
className="bg-transparent ml-4 flex-1 truncate outline-none placeholder:text-quaternary disabled:bg-primary disabled:text-tertiary"
onChange={extendedChange}
className="bg-transparent my-3 ml-4 flex-1 truncate outline-none placeholder:text-quaternary disabled:text-tertiary"
/>
<div className="my-1.5 mr-1.5">
<ActionButton
{...button}
onClick={() => button.onClick({ [name]: value })}
disabled={button.disabled || value === ''}
/>
</div>
{button && (
<div className="my-2 mr-2">
<ActionButton
{...button}
onClick={() => button.onClick({ [name]: value })}
disabled={button.disabled || value === ''}
/>
</div>
)}
</div>
);
};
Expand All @@ -144,7 +279,7 @@ export const ActionButton = ({
<CheckIcon />
</span>
);
return text;
return <Fragment>text</Fragment>;
};

return (
Expand Down
Loading

0 comments on commit 66ebcd6

Please sign in to comment.