mirror of
https://github.com/trezor/trezor-wallet
synced 2025-02-05 04:41:25 +00:00
Merge pull request #419 from trezor/feature/copy-log
Feature/Copy log to clipboard
This commit is contained in:
commit
bcfca51699
@ -39,6 +39,7 @@
|
||||
"color-hash": "^1.0.3",
|
||||
"commander": "^2.19.0",
|
||||
"connected-react-router": "6.0.0",
|
||||
"copy-to-clipboard": "^3.0.8",
|
||||
"copy-webpack-plugin": "^4.6.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"date-fns": "^1.30.1",
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
import * as LOG from 'actions/constants/log';
|
||||
import copy from 'copy-to-clipboard';
|
||||
|
||||
import type { Action, ThunkAction, GetState, Dispatch } from 'flowtype';
|
||||
import type { LogEntry } from 'reducers/LogReducer';
|
||||
@ -12,6 +13,12 @@ export type LogAction =
|
||||
| {
|
||||
type: typeof LOG.CLOSE,
|
||||
}
|
||||
| {
|
||||
type: typeof LOG.COPY_RESET,
|
||||
}
|
||||
| {
|
||||
type: typeof LOG.COPY_SUCCESS,
|
||||
}
|
||||
| {
|
||||
type: typeof LOG.ADD,
|
||||
payload: LogEntry,
|
||||
@ -39,3 +46,24 @@ export const add = (type: string, message: any): Action => ({
|
||||
message,
|
||||
},
|
||||
});
|
||||
|
||||
export const copyToClipboard = (): ThunkAction => (
|
||||
dispatch: Dispatch,
|
||||
getState: GetState
|
||||
): void => {
|
||||
const { entries } = getState().log;
|
||||
try {
|
||||
const res = copy(JSON.stringify(entries));
|
||||
if (res) {
|
||||
dispatch({
|
||||
type: LOG.COPY_SUCCESS,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
export const resetCopyState = (): Action => ({
|
||||
type: LOG.COPY_RESET,
|
||||
});
|
||||
|
@ -3,3 +3,5 @@
|
||||
export const OPEN: 'log__open' = 'log__open';
|
||||
export const CLOSE: 'log__close' = 'log__close';
|
||||
export const ADD: 'log__add' = 'log__add';
|
||||
export const COPY_SUCCESS: 'log__copy_success' = 'log__copy_success';
|
||||
export const COPY_RESET: 'log__copy_reset' = 'log__copy_reset';
|
||||
|
@ -5,6 +5,8 @@ import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import colors from 'config/colors';
|
||||
import { H2 } from 'components/Heading';
|
||||
import Button from 'components/Button';
|
||||
import Tooltip from 'components/Tooltip';
|
||||
import ReactJson from 'react-json-view';
|
||||
import Icon from 'components/Icon';
|
||||
import P from 'components/Paragraph';
|
||||
@ -18,6 +20,8 @@ import l10nMessages from './index.messages';
|
||||
type Props = {
|
||||
log: $ElementType<State, 'log'>,
|
||||
toggle: typeof LogActions.toggle,
|
||||
copyToClipboard: typeof LogActions.copyToClipboard,
|
||||
resetCopyState: typeof LogActions.resetCopyState,
|
||||
};
|
||||
|
||||
const Wrapper = styled.div`
|
||||
@ -59,8 +63,20 @@ const LogWrapper = styled.div`
|
||||
overflow: scroll;
|
||||
`;
|
||||
|
||||
const CopyWrapper = styled.div``;
|
||||
|
||||
const ButtonCopy = styled(Button)`
|
||||
margin-top: 10px;
|
||||
`;
|
||||
|
||||
const Log = (props: Props): ?React$Element<string> => {
|
||||
if (!props.log.opened) return null;
|
||||
|
||||
const copyBtn = (
|
||||
<ButtonCopy onClick={() => props.copyToClipboard()}>
|
||||
<FormattedMessage {...l10nMessages.TR_COPY_TO_CLIPBOARD} />
|
||||
</ButtonCopy>
|
||||
);
|
||||
return (
|
||||
<Wrapper>
|
||||
<Click onClick={props.toggle}>
|
||||
@ -75,6 +91,19 @@ const Log = (props: Props): ?React$Element<string> => {
|
||||
<LogWrapper>
|
||||
<ReactJson src={props.log.entries} />
|
||||
</LogWrapper>
|
||||
{props.log.copied ? (
|
||||
<Tooltip
|
||||
defaultVisible
|
||||
maxWidth={285}
|
||||
placement="top"
|
||||
content={<FormattedMessage {...l10nMessages.TR_COPIED} />}
|
||||
afterVisibleChange={props.resetCopyState}
|
||||
>
|
||||
{copyBtn}
|
||||
</Tooltip>
|
||||
) : (
|
||||
<CopyWrapper>{copyBtn}</CopyWrapper>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
@ -85,5 +114,7 @@ export default connect(
|
||||
}),
|
||||
(dispatch: Dispatch) => ({
|
||||
toggle: bindActionCreators(LogActions.toggle, dispatch),
|
||||
copyToClipboard: bindActionCreators(LogActions.copyToClipboard, dispatch),
|
||||
resetCopyState: bindActionCreators(LogActions.resetCopyState, dispatch),
|
||||
})
|
||||
)(Log);
|
||||
|
@ -13,6 +13,14 @@ const definedMessages: Messages = defineMessages({
|
||||
defaultMessage: 'Log',
|
||||
description: 'application event and error',
|
||||
},
|
||||
TR_COPY_TO_CLIPBOARD: {
|
||||
id: 'TR_COPY_TO_CLIPBOARD',
|
||||
defaultMessage: 'Copy to clipboard',
|
||||
},
|
||||
TR_COPIED: {
|
||||
id: 'TR_COPIED',
|
||||
defaultMessage: 'Copied!',
|
||||
},
|
||||
});
|
||||
|
||||
export default definedMessages;
|
||||
|
@ -34,12 +34,15 @@ const Tooltip = ({
|
||||
readMoreLink,
|
||||
children,
|
||||
enterDelayMs,
|
||||
defaultVisible = false,
|
||||
...rest
|
||||
}) => (
|
||||
<Wrapper className={className}>
|
||||
<RcTooltip
|
||||
arrowContent={<div className="rc-tooltip-arrow-inner" />}
|
||||
placement={placement}
|
||||
mouseEnterDelay={enterDelayMs || 0}
|
||||
defaultVisible={defaultVisible}
|
||||
overlay={() => (
|
||||
<ContentWrapper>
|
||||
<Content maxWidth={maxWidth}>{content}</Content>
|
||||
@ -52,6 +55,7 @@ const Tooltip = ({
|
||||
)}
|
||||
</ContentWrapper>
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</RcTooltip>
|
||||
@ -66,6 +70,7 @@ Tooltip.propTypes = {
|
||||
content: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
|
||||
readMoreLink: PropTypes.string,
|
||||
enterDelayMs: PropTypes.number,
|
||||
defaultVisible: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Tooltip;
|
||||
|
@ -12,11 +12,13 @@ export type LogEntry = {
|
||||
export type State = {
|
||||
opened: boolean,
|
||||
entries: Array<LogEntry>,
|
||||
copied: boolean,
|
||||
};
|
||||
|
||||
export const initialState: State = {
|
||||
opened: false,
|
||||
entries: [],
|
||||
copied: false,
|
||||
};
|
||||
|
||||
export default (state: State = initialState, action: Action): State => {
|
||||
@ -31,6 +33,7 @@ export default (state: State = initialState, action: Action): State => {
|
||||
return {
|
||||
...state,
|
||||
opened: false,
|
||||
copied: false,
|
||||
};
|
||||
|
||||
case LOG.ADD:
|
||||
@ -39,6 +42,18 @@ export default (state: State = initialState, action: Action): State => {
|
||||
entries: state.entries.concat([action.payload]),
|
||||
};
|
||||
|
||||
case LOG.COPY_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
copied: true,
|
||||
};
|
||||
|
||||
case LOG.COPY_RESET:
|
||||
return {
|
||||
...state,
|
||||
copied: false,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
12
yarn.lock
12
yarn.lock
@ -3114,6 +3114,13 @@ copy-descriptor@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
|
||||
|
||||
copy-to-clipboard@^3.0.8:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9"
|
||||
integrity sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw==
|
||||
dependencies:
|
||||
toggle-selection "^1.0.3"
|
||||
|
||||
copy-webpack-plugin@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae"
|
||||
@ -11076,6 +11083,11 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
||||
regex-not "^1.0.2"
|
||||
safe-regex "^1.1.0"
|
||||
|
||||
toggle-selection@^1.0.3:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
|
||||
integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI=
|
||||
|
||||
toposort@^1.0.0:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
|
||||
|
Loading…
Reference in New Issue
Block a user