aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorLibravatar André Oliveira <37463445+SpecialAro@users.noreply.github.com>2022-07-19 12:52:31 +0100
committerLibravatar GitHub <noreply@github.com>2022-07-19 12:52:31 +0100
commit3bb1ca7825a0381ddd8dbe7f44f7dcf4a788b165 (patch)
tree6b414b9ef3be7656da1717b0d6def62e95d1fb90 /src/components
parentfix: remove autoHibernate (diff)
downloadferdium-app-3bb1ca7825a0381ddd8dbe7f44f7dcf4a788b165.tar.gz
ferdium-app-3bb1ca7825a0381ddd8dbe7f44f7dcf4a788b165.tar.zst
ferdium-app-3bb1ca7825a0381ddd8dbe7f44f7dcf4a788b165.zip
Feature: Add Release Notes (#491)
Co-authored-by: Vijay A <vraravam@users.noreply.github.com> Co-authored-by: Ricardo Cino <ricardo@cino.io>
Diffstat (limited to 'src/components')
-rw-r--r--src/components/AppUpdateInfoBar.tsx23
-rw-r--r--src/components/auth/AuthLayout.jsx5
-rw-r--r--src/components/layout/AppLayout.jsx (renamed from src/components/layout/AppLayout.js)166
-rw-r--r--src/components/settings/SettingsLayout.jsx4
-rw-r--r--src/components/settings/navigation/SettingsNavigation.jsx24
-rw-r--r--src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx99
-rw-r--r--src/components/settings/releaseNotes/ReleaseNotesLayout.tsx79
-rw-r--r--src/components/settings/settings/EditSettingsForm.jsx31
-rw-r--r--src/components/ui/effects/Appear.tsx10
9 files changed, 341 insertions, 100 deletions
diff --git a/src/components/AppUpdateInfoBar.tsx b/src/components/AppUpdateInfoBar.tsx
index 48efbfb7f..3ff488b74 100644
--- a/src/components/AppUpdateInfoBar.tsx
+++ b/src/components/AppUpdateInfoBar.tsx
@@ -2,10 +2,10 @@ import { defineMessages, useIntl } from 'react-intl';
2 2
3import { mdiInformation } from '@mdi/js'; 3import { mdiInformation } from '@mdi/js';
4import InfoBar from './ui/InfoBar'; 4import InfoBar from './ui/InfoBar';
5import { GITHUB_FERDIUM_URL } from '../config';
6import { openExternalUrl } from '../helpers/url-helpers';
7import Icon from './ui/icon'; 5import Icon from './ui/icon';
8 6
7import { onAuthGoToReleaseNotes } from '../helpers/update-helpers';
8
9const messages = defineMessages({ 9const messages = defineMessages({
10 updateAvailable: { 10 updateAvailable: {
11 id: 'infobar.updateAvailable', 11 id: 'infobar.updateAvailable',
@@ -24,9 +24,14 @@ const messages = defineMessages({
24type Props = { 24type Props = {
25 onInstallUpdate: () => void; 25 onInstallUpdate: () => void;
26 onHide: () => void; 26 onHide: () => void;
27 updateVersionParsed: string;
27}; 28};
28 29
29const AppUpdateInfoBar = ({ onInstallUpdate, onHide }: Props) => { 30const AppUpdateInfoBar = ({
31 onInstallUpdate,
32 updateVersionParsed,
33 onHide,
34}: Props) => {
30 const intl = useIntl(); 35 const intl = useIntl();
31 36
32 return ( 37 return (
@@ -41,12 +46,12 @@ const AppUpdateInfoBar = ({ onInstallUpdate, onHide }: Props) => {
41 <button 46 <button
42 className="info-bar__inline-button" 47 className="info-bar__inline-button"
43 type="button" 48 type="button"
44 onClick={() => 49 onClick={() => {
45 openExternalUrl( 50 window.location.href = onAuthGoToReleaseNotes(
46 `${GITHUB_FERDIUM_URL}/ferdium-app/blob/develop/CHANGELOG.md`, 51 window.location.href,
47 true, 52 updateVersionParsed,
48 ) 53 );
49 } 54 }}
50 > 55 >
51 <u>{intl.formatMessage(messages.changelog)}</u> 56 <u>{intl.formatMessage(messages.changelog)}</u>
52 </button> 57 </button>
diff --git a/src/components/auth/AuthLayout.jsx b/src/components/auth/AuthLayout.jsx
index 8a88cedb1..5c87c3080 100644
--- a/src/components/auth/AuthLayout.jsx
+++ b/src/components/auth/AuthLayout.jsx
@@ -14,6 +14,7 @@ import {
14 oneOrManyChildElements, 14 oneOrManyChildElements,
15 globalError as globalErrorPropType, 15 globalError as globalErrorPropType,
16} from '../../prop-types'; 16} from '../../prop-types';
17import { updateVersionParse } from '../../helpers/update-helpers';
17import globalMessages from '../../i18n/globalMessages'; 18import globalMessages from '../../i18n/globalMessages';
18 19
19import { isWindows } from '../../environment'; 20import { isWindows } from '../../environment';
@@ -34,6 +35,7 @@ class AuthLayout extends Component {
34 isFullScreen: PropTypes.bool.isRequired, 35 isFullScreen: PropTypes.bool.isRequired,
35 installAppUpdate: PropTypes.func.isRequired, 36 installAppUpdate: PropTypes.func.isRequired,
36 appUpdateIsDownloaded: PropTypes.bool.isRequired, 37 appUpdateIsDownloaded: PropTypes.bool.isRequired,
38 updateVersion: PropTypes.string.isRequired,
37 }; 39 };
38 40
39 constructor() { 41 constructor() {
@@ -55,10 +57,10 @@ class AuthLayout extends Component {
55 isFullScreen, 57 isFullScreen,
56 installAppUpdate, 58 installAppUpdate,
57 appUpdateIsDownloaded, 59 appUpdateIsDownloaded,
60 updateVersion,
58 } = this.props; 61 } = this.props;
59 62
60 const { intl } = this.props; 63 const { intl } = this.props;
61
62 let serverNameParse = serverName(); 64 let serverNameParse = serverName();
63 serverNameParse = 65 serverNameParse =
64 serverNameParse === 'Custom' ? 'your Custom Server' : serverNameParse; 66 serverNameParse === 'Custom' ? 'your Custom Server' : serverNameParse;
@@ -81,6 +83,7 @@ class AuthLayout extends Component {
81 {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( 83 {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && (
82 <AppUpdateInfoBar 84 <AppUpdateInfoBar
83 onInstallUpdate={installAppUpdate} 85 onInstallUpdate={installAppUpdate}
86 updateVersionParsed={updateVersionParse(updateVersion)}
84 onHide={() => { 87 onHide={() => {
85 this.setState({ shouldShowAppUpdateInfoBar: false }); 88 this.setState({ shouldShowAppUpdateInfoBar: false });
86 }} 89 }}
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.jsx
index f7860afc6..685839c0a 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.jsx
@@ -13,6 +13,7 @@ import { Component as BasicAuth } from '../../features/basicAuth';
13import { Component as QuickSwitch } from '../../features/quickSwitch'; 13import { Component as QuickSwitch } from '../../features/quickSwitch';
14import { Component as PublishDebugInfo } from '../../features/publishDebugInfo'; 14import { Component as PublishDebugInfo } from '../../features/publishDebugInfo';
15import ErrorBoundary from '../util/ErrorBoundary'; 15import ErrorBoundary from '../util/ErrorBoundary';
16import { updateVersionParse } from '../../helpers/update-helpers';
16 17
17// import globalMessages from '../../i18n/globalMessages'; 18// import globalMessages from '../../i18n/globalMessages';
18 19
@@ -94,10 +95,14 @@ class AppLayout extends Component {
94 areRequiredRequestsLoading: PropTypes.bool.isRequired, 95 areRequiredRequestsLoading: PropTypes.bool.isRequired,
95 }; 96 };
96 97
97 state = { 98 constructor(props) {
98 shouldShowAppUpdateInfoBar: true, 99 super(props);
99 shouldShowServicesUpdatedInfoBar: true, 100
100 }; 101 this.state = {
102 shouldShowAppUpdateInfoBar: true,
103 shouldShowServicesUpdatedInfoBar: true,
104 };
105 }
101 106
102 render() { 107 render() {
103 const { 108 const {
@@ -115,6 +120,7 @@ class AppLayout extends Component {
115 areRequiredRequestsSuccessful, 120 areRequiredRequestsSuccessful,
116 retryRequiredRequests, 121 retryRequiredRequests,
117 areRequiredRequestsLoading, 122 areRequiredRequestsLoading,
123 updateVersion,
118 } = this.props; 124 } = this.props;
119 125
120 const { intl } = this.props; 126 const { intl } = this.props;
@@ -126,86 +132,90 @@ class AppLayout extends Component {
126 132
127 return ( 133 return (
128 <> 134 <>
129 {isMac && !isFullScreen && ( 135 {isMac && !isFullScreen && <div className="window-draggable" />}
130 <div className="window-draggable" /> 136 <ErrorBoundary>
131 )} 137 <div className="app">
132 <ErrorBoundary> 138 {isWindows && !isFullScreen && (
133 <div className="app"> 139 <TitleBar
134 {isWindows && !isFullScreen && ( 140 menu={window['ferdium'].menu.template}
135 <TitleBar 141 icon="assets/images/logo.svg"
136 menu={window['ferdium'].menu.template} 142 />
137 icon="assets/images/logo.svg" 143 )}
138 /> 144 {isMac && !isFullScreen && (
139 )} 145 <span
140 {isMac && !isFullScreen && ( 146 onDoubleClick={toggleFullScreen}
141 <span 147 className={classes.titleBar}
142 onDoubleClick={toggleFullScreen} 148 />
143 className={classes.titleBar} 149 )}
144 /> 150 <div className={`app__content ${classes.appContent}`}>
145 )} 151 {workspacesDrawer}
146 <div className={`app__content ${classes.appContent}`}> 152 {sidebar}
147 {workspacesDrawer} 153 <div className="app__service">
148 {sidebar} 154 <WorkspaceSwitchingIndicator />
149 <div className="app__service"> 155 {!areRequiredRequestsSuccessful && showRequiredRequestsError && (
150 <WorkspaceSwitchingIndicator /> 156 <InfoBar
151 {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( 157 type="danger"
152 <InfoBar 158 ctaLabel="Try again"
153 type="danger" 159 ctaLoading={areRequiredRequestsLoading}
154 ctaLabel="Try again" 160 sticky
155 ctaLoading={areRequiredRequestsLoading} 161 onClick={retryRequiredRequests}
156 sticky 162 >
157 onClick={retryRequiredRequests} 163 <Icon icon={mdiFlash} />
158 > 164 {intl.formatMessage(messages.requiredRequestsFailed)}
159 <Icon icon={mdiFlash} /> 165 </InfoBar>
160 {intl.formatMessage(messages.requiredRequestsFailed)} 166 )}
161 </InfoBar> 167 {authRequestFailed && (
162 )}
163 {authRequestFailed && (
164 <InfoBar
165 type="danger"
166 ctaLabel="Try again"
167 ctaLoading={areRequiredRequestsLoading}
168 sticky
169 onClick={retryRequiredRequests}
170 >
171 <Icon icon={mdiFlash} />
172 {intl.formatMessage(messages.authRequestFailed)}
173 </InfoBar>
174 )}
175 {automaticUpdates && showServicesUpdatedInfoBar &&
176 this.state.shouldShowServicesUpdatedInfoBar && (
177 <InfoBar 168 <InfoBar
178 type="primary" 169 type="danger"
179 ctaLabel={intl.formatMessage(messages.buttonReloadServices)} 170 ctaLabel="Try again"
180 onClick={() => window.location.reload()} 171 ctaLoading={areRequiredRequestsLoading}
181 onHide={() => { 172 sticky
182 this.setState({ 173 onClick={retryRequiredRequests}
183 shouldShowServicesUpdatedInfoBar: false,
184 });
185 }}
186 > 174 >
187 <Icon icon={mdiPowerPlug} /> 175 <Icon icon={mdiFlash} />
188 {intl.formatMessage(messages.servicesUpdated)} 176 {intl.formatMessage(messages.authRequestFailed)}
189 </InfoBar> 177 </InfoBar>
190 )} 178 )}
191 {automaticUpdates && appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( 179 {automaticUpdates &&
192 <AppUpdateInfoBar 180 showServicesUpdatedInfoBar &&
193 onInstallUpdate={installAppUpdate} 181 this.state.shouldShowServicesUpdatedInfoBar && (
194 onHide={() => { 182 <InfoBar
195 this.setState({ shouldShowAppUpdateInfoBar: false }); 183 type="primary"
196 }} 184 ctaLabel={intl.formatMessage(
197 /> 185 messages.buttonReloadServices,
198 )} 186 )}
199 <BasicAuth /> 187 onClick={() => window.location.reload()}
200 <QuickSwitch /> 188 onHide={() => {
201 <PublishDebugInfo /> 189 this.setState({
202 {services} 190 shouldShowServicesUpdatedInfoBar: false,
203 <Outlet /> 191 });
192 }}
193 >
194 <Icon icon={mdiPowerPlug} />
195 {intl.formatMessage(messages.servicesUpdated)}
196 </InfoBar>
197 )}
198 {automaticUpdates &&
199 appUpdateIsDownloaded &&
200 this.state.shouldShowAppUpdateInfoBar && (
201 <AppUpdateInfoBar
202 onInstallUpdate={installAppUpdate}
203 updateVersionParsed={updateVersionParse(updateVersion)}
204 onHide={() => {
205 this.setState({ shouldShowAppUpdateInfoBar: false });
206 }}
207 />
208 )}
209 <BasicAuth />
210 <QuickSwitch />
211 <PublishDebugInfo />
212 {services}
213 <Outlet />
214 </div>
215 <Todos />
204 </div> 216 </div>
205 <Todos />
206 </div> 217 </div>
207 </div> 218 </ErrorBoundary>
208 </ErrorBoundary>
209 </> 219 </>
210 ); 220 );
211 } 221 }
diff --git a/src/components/settings/SettingsLayout.jsx b/src/components/settings/SettingsLayout.jsx
index dea4bb387..989c428f2 100644
--- a/src/components/settings/SettingsLayout.jsx
+++ b/src/components/settings/SettingsLayout.jsx
@@ -8,6 +8,7 @@ import { Outlet } from 'react-router-dom';
8import ErrorBoundary from '../util/ErrorBoundary'; 8import ErrorBoundary from '../util/ErrorBoundary';
9import Appear from '../ui/effects/Appear'; 9import Appear from '../ui/effects/Appear';
10import Icon from '../ui/icon'; 10import Icon from '../ui/icon';
11import { isEscKeyPress } from '../../jsUtils';
11 12
12const messages = defineMessages({ 13const messages = defineMessages({
13 closeSettings: { 14 closeSettings: {
@@ -36,8 +37,7 @@ class SettingsLayout extends Component {
36 } 37 }
37 38
38 handleKeyDown(e) { 39 handleKeyDown(e) {
39 if (e.keyCode === 27) { 40 if (isEscKeyPress(e.keyCode)) {
40 // escape key
41 this.props.closeSettings(); 41 this.props.closeSettings();
42 } 42 }
43 } 43 }
diff --git a/src/components/settings/navigation/SettingsNavigation.jsx b/src/components/settings/navigation/SettingsNavigation.jsx
index bbbe8d888..e1242a7fe 100644
--- a/src/components/settings/navigation/SettingsNavigation.jsx
+++ b/src/components/settings/navigation/SettingsNavigation.jsx
@@ -5,7 +5,11 @@ import { inject, observer } from 'mobx-react';
5import { RouterStore } from '@superwf/mobx-react-router'; 5import { RouterStore } from '@superwf/mobx-react-router';
6 6
7import { NavLink } from 'react-router-dom'; 7import { NavLink } from 'react-router-dom';
8import { LOCAL_SERVER, LIVE_FERDIUM_API, LIVE_FRANZ_API } from '../../../config'; 8import {
9 LOCAL_SERVER,
10 LIVE_FERDIUM_API,
11 LIVE_FRANZ_API,
12} from '../../../config';
9import UIStore from '../../../stores/UIStore'; 13import UIStore from '../../../stores/UIStore';
10import SettingsStore from '../../../stores/SettingsStore'; 14import SettingsStore from '../../../stores/SettingsStore';
11import UserStore from '../../../stores/UserStore'; 15import UserStore from '../../../stores/UserStore';
@@ -32,6 +36,10 @@ const messages = defineMessages({
32 id: 'settings.navigation.team', 36 id: 'settings.navigation.team',
33 defaultMessage: 'Manage Team', 37 defaultMessage: 'Manage Team',
34 }, 38 },
39 releaseNotes: {
40 id: 'settings.navigation.releaseNotes',
41 defaultMessage: 'Release Notes',
42 },
35 supportFerdium: { 43 supportFerdium: {
36 id: 'settings.navigation.supportFerdium', 44 id: 'settings.navigation.supportFerdium',
37 defaultMessage: 'About Ferdium', 45 defaultMessage: 'About Ferdium',
@@ -165,6 +173,16 @@ class SettingsNavigation extends Component {
165 )} 173 )}
166 </NavLink> 174 </NavLink>
167 <NavLink 175 <NavLink
176 to="/settings/releasenotes"
177 className={({ isActive }) =>
178 isActive
179 ? 'settings-navigation__link is-active'
180 : 'settings-navigation__link'
181 }
182 >
183 {intl.formatMessage(messages.releaseNotes)}
184 </NavLink>
185 <NavLink
168 to="/settings/support" 186 to="/settings/support"
169 className={({ isActive }) => 187 className={({ isActive }) =>
170 isActive 188 isActive
@@ -190,4 +208,6 @@ class SettingsNavigation extends Component {
190 } 208 }
191} 209}
192 210
193export default injectIntl(inject('stores', 'actions')(observer(SettingsNavigation))); 211export default injectIntl(
212 inject('stores', 'actions')(observer(SettingsNavigation)),
213);
diff --git a/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx b/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx
new file mode 100644
index 000000000..d0be82312
--- /dev/null
+++ b/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx
@@ -0,0 +1,99 @@
1import { Component } from 'react';
2import { observer } from 'mobx-react';
3import { defineMessages, injectIntl } from 'react-intl';
4import Markdown from 'markdown-to-jsx';
5import { openExternalUrl } from '../../../helpers/url-helpers';
6import { ferdiumVersion } from '../../../environment-remote';
7import {
8 getFerdiumVersion,
9 getUpdateInfoFromGH,
10} from '../../../helpers/update-helpers';
11
12const messages = defineMessages({
13 headline: {
14 id: 'settings.releasenotes.headline',
15 defaultMessage: 'Release Notes',
16 },
17 connectionError: {
18 id: 'settings.releasenotes.connectionError',
19 defaultMessage:
20 'An error occured when connecting to Github, please try again later.',
21 },
22 connectionErrorPageMissing: {
23 id: 'settings.releasenotes.connectionErrorPageMissing',
24 defaultMessage:
25 'An error occured when connecting to Github, the page you are looking for is missing.',
26 },
27});
28
29interface IProps {
30 intl: any;
31}
32
33class ReleaseNotesDashboard extends Component<IProps> {
34 state = {
35 data: '',
36 };
37
38 constructor(props) {
39 super(props);
40
41 this.state = { data: '' };
42 }
43
44 async componentDidMount() {
45 const { intl } = this.props;
46
47 const data = await getUpdateInfoFromGH(
48 window.location.href,
49 ferdiumVersion,
50 intl,
51 );
52
53 this.setState({
54 data,
55 });
56
57 for (const link of document.querySelectorAll('.releasenotes__body a')) {
58 link.addEventListener('click', this.handleClick.bind(this), false);
59 }
60 }
61
62 handleClick(e) {
63 e.preventDefault();
64 openExternalUrl(e.target.href);
65 }
66
67 componentWillUnmount() {
68 document.removeEventListener(
69 'click',
70 // eslint-disable-next-line unicorn/no-invalid-remove-event-listener
71 this.handleClick.bind(this),
72 false,
73 );
74 }
75
76 render() {
77 const { intl } = this.props;
78
79 const { data } = this.state;
80 return (
81 <div className="settings__main">
82 <div className="settings__header">
83 <span className="settings__header-item">
84 Ferdium {getFerdiumVersion(window.location.href, ferdiumVersion)}{' '}
85 {' | '}
86 </span>
87 <span className="settings__header-item__secondary">
88 {intl.formatMessage(messages.headline)}
89 </span>
90 </div>
91 <div className="settings__body releasenotes__body">
92 <Markdown options={{ wrapper: 'article' }}>{data}</Markdown>
93 </div>
94 </div>
95 );
96 }
97}
98
99export default injectIntl(observer(ReleaseNotesDashboard));
diff --git a/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx b/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx
new file mode 100644
index 000000000..ee0ba75a8
--- /dev/null
+++ b/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx
@@ -0,0 +1,79 @@
1import { Component } from 'react';
2import { inject, observer } from 'mobx-react';
3import { defineMessages, injectIntl } from 'react-intl';
4
5import { mdiClose } from '@mdi/js';
6import { Outlet } from 'react-router-dom';
7import { StoresProps } from '../../../@types/ferdium-components.types';
8import ErrorBoundary from '../../util/ErrorBoundary';
9import Appear from '../../ui/effects/Appear';
10import Icon from '../../ui/icon';
11import { isEscKeyPress } from '../../../jsUtils';
12
13const messages = defineMessages({
14 closeSettings: {
15 id: 'settings.app.closeSettings',
16 defaultMessage: 'Close settings',
17 },
18});
19
20interface IProps extends StoresProps {
21 intl: any;
22}
23
24class ReleaseNotesLayout extends Component<IProps> {
25 componentDidMount() {
26 document.addEventListener('keydown', this.handleKeyDown.bind(this), false);
27 }
28
29 componentWillUnmount() {
30 document.removeEventListener(
31 'keydown',
32 // eslint-disable-next-line unicorn/no-invalid-remove-event-listener
33 this.handleKeyDown.bind(this),
34 false,
35 );
36 }
37
38 handleKeyDown(e) {
39 if (isEscKeyPress(e.keyCode)) {
40 this.props.actions.ui.closeSettings();
41 }
42 }
43
44 render() {
45 const { closeSettings } = this.props.actions.ui;
46
47 const { intl } = this.props;
48
49 return (
50 <Appear transitionName="fadeIn-fast">
51 <div className="settings-wrapper">
52 <ErrorBoundary>
53 <button
54 type="button"
55 className="settings-wrapper__action"
56 onClick={closeSettings}
57 aria-label={intl.formatMessage(messages.closeSettings)}
58 />
59 <div className="settings franz-form">
60 <Outlet />
61 <button
62 type="button"
63 className="settings__close"
64 onClick={closeSettings}
65 aria-label={intl.formatMessage(messages.closeSettings)}
66 >
67 <Icon icon={mdiClose} size={1.35} />
68 </button>
69 </div>
70 </ErrorBoundary>
71 </div>
72 </Appear>
73 );
74 }
75}
76
77export default injectIntl<'intl', IProps>(
78 inject('stores', 'actions')(observer(ReleaseNotesLayout)),
79);
diff --git a/src/components/settings/settings/EditSettingsForm.jsx b/src/components/settings/settings/EditSettingsForm.jsx
index cb1d261f8..a10d89570 100644
--- a/src/components/settings/settings/EditSettingsForm.jsx
+++ b/src/components/settings/settings/EditSettingsForm.jsx
@@ -15,6 +15,13 @@ import Input from '../../ui/Input';
15import ColorPickerInput from '../../ui/ColorPickerInput'; 15import ColorPickerInput from '../../ui/ColorPickerInput';
16import Infobox from '../../ui/Infobox'; 16import Infobox from '../../ui/Infobox';
17import { H1, H2, H3, H5 } from '../../ui/headline'; 17import { H1, H2, H3, H5 } from '../../ui/headline';
18import {
19 ferdiumVersion,
20 userDataPath,
21 userDataRecipesPath,
22} from '../../../environment-remote';
23
24import { updateVersionParse } from '../../../helpers/update-helpers';
18 25
19import { 26import {
20 DEFAULT_ACCENT_COLOR, 27 DEFAULT_ACCENT_COLOR,
@@ -25,11 +32,6 @@ import {
25 SPLIT_COLUMNS_MIN, 32 SPLIT_COLUMNS_MIN,
26} from '../../../config'; 33} from '../../../config';
27import { isMac, isWindows, lockFerdiumShortcutKey } from '../../../environment'; 34import { isMac, isWindows, lockFerdiumShortcutKey } from '../../../environment';
28import {
29 ferdiumVersion,
30 userDataPath,
31 userDataRecipesPath,
32} from '../../../environment-remote';
33import { openExternalUrl, openPath } from '../../../helpers/url-helpers'; 35import { openExternalUrl, openPath } from '../../../helpers/url-helpers';
34import globalMessages from '../../../i18n/globalMessages'; 36import globalMessages from '../../../i18n/globalMessages';
35import Icon from '../../ui/icon'; 37import Icon from '../../ui/icon';
@@ -213,6 +215,10 @@ const messages = defineMessages({
213 id: 'settings.app.buttonInstallUpdate', 215 id: 'settings.app.buttonInstallUpdate',
214 defaultMessage: 'Restart & install update', 216 defaultMessage: 'Restart & install update',
215 }, 217 },
218 buttonShowChangelog: {
219 id: 'settings.app.buttonShowChangelog',
220 defaultMessage: 'Show changelog',
221 },
216 updateStatusSearching: { 222 updateStatusSearching: {
217 id: 'settings.app.updateStatusSearching', 223 id: 'settings.app.updateStatusSearching',
218 defaultMessage: 'Searching for updates...', 224 defaultMessage: 'Searching for updates...',
@@ -328,6 +334,7 @@ class EditSettingsForm extends Component {
328 checkForUpdates, 334 checkForUpdates,
329 installUpdate, 335 installUpdate,
330 form, 336 form,
337 updateVersion,
331 isCheckingForUpdates, 338 isCheckingForUpdates,
332 isAdaptableDarkModeEnabled, 339 isAdaptableDarkModeEnabled,
333 isUseGrayscaleServicesEnabled, 340 isUseGrayscaleServicesEnabled,
@@ -1002,6 +1009,20 @@ class EditSettingsForm extends Component {
1002 loaded={!isCheckingForUpdates || !isUpdateAvailable} 1009 loaded={!isCheckingForUpdates || !isUpdateAvailable}
1003 /> 1010 />
1004 )} 1011 )}
1012 {(isUpdateAvailable || updateIsReadyToInstall) && (
1013 <Button
1014 className="settings__updates__changelog-button"
1015 label={intl.formatMessage(
1016 messages.buttonShowChangelog,
1017 )}
1018 onClick={() => {
1019 window.location.href = `#/releasenotes${updateVersionParse(
1020 updateVersion,
1021 )}`;
1022 }}
1023 />
1024 )}
1025 <br />
1005 <br /> 1026 <br />
1006 </div> 1027 </div>
1007 <p> 1028 <p>
diff --git a/src/components/ui/effects/Appear.tsx b/src/components/ui/effects/Appear.tsx
index 117c02f97..228c7888a 100644
--- a/src/components/ui/effects/Appear.tsx
+++ b/src/components/ui/effects/Appear.tsx
@@ -1,10 +1,10 @@
1import { ReactChildren, useEffect, useState } from 'react'; 1import { ReactNode, useEffect, useState } from 'react';
2import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; 2import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
3 3
4type Props = { 4type Props = {
5 children: ReactChildren; 5 children: ReactNode;
6 transitionName: string; 6 transitionName: string;
7 className: string; 7 className?: string;
8}; 8};
9const Appear = ({ 9const Appear = ({
10 children, 10 children,
@@ -36,4 +36,8 @@ const Appear = ({
36 ); 36 );
37}; 37};
38 38
39Appear.defaultProps = {
40 className: '',
41};
42
39export default Appear; 43export default Appear;