diff --git a/public/backend-config.json b/public/backend-config.json
index dcb01bf57..61dff0024 100644
--- a/public/backend-config.json
+++ b/public/backend-config.json
@@ -22,5 +22,10 @@
"privacy": "test",
"termsOfUse": "test",
"imprint": "test"
+ },
+ "version": {
+ "version": "mock",
+ "sourceCodeUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
+ "issueTrackerUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}
}
diff --git a/public/locales/en.json b/public/locales/en.json
index a1ab6d697..c133c4a11 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -115,7 +115,7 @@
"deleteUser": "Delete user",
"exportUserData": "Export user data",
"Help us translating on %s": "Help us translating on %s",
- "sourceCode": "Source Code",
+ "sourceCode": "Read the source code",
"Register": "Register",
"poweredBy": "Powered by <0>0>",
"Help us translating": "Help us translating",
@@ -128,5 +128,12 @@
"username": "Username",
"cards": "Cards",
"table": "Table",
- "errorOpenIdLogin": "Invalid OpenID provided"
+ "errorOpenIdLogin": "Invalid OpenID provided",
+ "versionInfo": "Version info",
+ "successfullyCopied": "Copied!",
+ "serverVersion": "Server version",
+ "clientVersion": "Client version",
+ "youAreUsing": "You are using",
+ "close": "Close",
+ "issueTracker": "Found a bug? Fill an issue!"
}
diff --git a/src/components/landing/layout/footer/powered-by-links.tsx b/src/components/landing/layout/footer/powered-by-links.tsx
index 05a414a4d..2f18b6158 100644
--- a/src/components/landing/layout/footer/powered-by-links.tsx
+++ b/src/components/landing/layout/footer/powered-by-links.tsx
@@ -1,35 +1,36 @@
-import { Trans, useTranslation } from 'react-i18next'
-import { TranslatedLink } from './translated-link'
import React, { Fragment } from 'react'
-import { ExternalLink } from './external-link'
+import { Trans, useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { ApplicationState } from '../../../../redux'
+import { ExternalLink } from '../../../links/external-link'
+import { TranslatedExternalLink } from '../../../links/translated-external-link'
+import { VersionInfo } from '../version-info/version-info'
export const PoweredByLinks: React.FC = () => {
useTranslation()
const defaultLinks =
{
- releases: '/s/release-notes',
- sourceCode: 'https://github.com/codimd/server/tree/41b13e71b6b1d499238c04b15d65e3bd76442f1d'
+ releases: '/n/release-notes'
}
const config = useSelector((state: ApplicationState) => state.backendConfig)
return (
- ]}/>
+
+
+
{
Object.entries({ ...defaultLinks, ...(config.specialLinks) }).map(([i18nKey, href]) =>
|
-
+
)
}
+ |
+
)
}
diff --git a/src/components/landing/layout/footer/social-links.tsx b/src/components/landing/layout/footer/social-links.tsx
index e7a4007d7..2db3fff54 100644
--- a/src/components/landing/layout/footer/social-links.tsx
+++ b/src/components/landing/layout/footer/social-links.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import { Trans, useTranslation } from 'react-i18next'
-import { ExternalLink } from './external-link'
+import { ExternalLink } from '../../../links/external-link'
const SocialLink: React.FC = () => {
useTranslation()
diff --git a/src/components/landing/layout/footer/translated-link.tsx b/src/components/landing/layout/footer/translated-link.tsx
deleted file mode 100644
index 288b26ce1..000000000
--- a/src/components/landing/layout/footer/translated-link.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react'
-import { Trans, useTranslation } from 'react-i18next'
-
-export interface TranslatedLinkProps {
- href: string;
- i18nKey: string;
-}
-
-const TranslatedLink: React.FC = ({ href, i18nKey }) => {
- useTranslation()
- return (
-
-
-
- )
-}
-
-export { TranslatedLink }
diff --git a/src/components/landing/layout/version-info/version-info.tsx b/src/components/landing/layout/version-info/version-info.tsx
new file mode 100644
index 000000000..7fcec0978
--- /dev/null
+++ b/src/components/landing/layout/version-info/version-info.tsx
@@ -0,0 +1,51 @@
+import React, { Fragment, useState } from 'react'
+import { Button, Col, Modal, Row } from 'react-bootstrap'
+import { Trans, useTranslation } from 'react-i18next'
+import { useSelector } from 'react-redux'
+import { Link } from 'react-router-dom'
+import { ApplicationState } from '../../../../redux'
+import frontendVersion from '../../../../version.json'
+import { TranslatedExternalLink } from '../../../links/translated-external-link'
+import { VersionInputField } from './version-input-field'
+
+export const VersionInfo: React.FC = () => {
+ const [show, setShow] = useState(false)
+
+ const handleClose = () => setShow(false)
+ const handleShow = () => setShow(true)
+
+ const { t } = useTranslation()
+
+ const serverVersion = useSelector((state: ApplicationState) => state.backendConfig.version)
+
+ const column = (title: string, version: string, sourceCodeLink: string, issueTrackerLink: string) => (
+
+ {title}
+
+ {sourceCodeLink
+ ? : null}
+ {issueTrackerLink
+ ? : null}
+
+ )
+
+ return (
+
+
+
+
+
+
+ {column(t('serverVersion'), serverVersion.version, serverVersion.sourceCodeUrl, serverVersion.issueTrackerUrl)}
+ {column(t('clientVersion'), frontendVersion.version, frontendVersion.sourceCodeUrl, frontendVersion.issueTrackerUrl)}
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/landing/layout/version-info/version-input-field.tsx b/src/components/landing/layout/version-info/version-input-field.tsx
new file mode 100644
index 000000000..9b3364e04
--- /dev/null
+++ b/src/components/landing/layout/version-info/version-input-field.tsx
@@ -0,0 +1,43 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import React, { Fragment, useRef, useState } from 'react'
+import { Button, FormControl, InputGroup, Overlay, Tooltip } from 'react-bootstrap'
+import { Trans } from 'react-i18next'
+
+export interface VersionInputFieldProps {
+ version: string
+}
+
+export const VersionInputField: React.FC = ({ version }) => {
+ const inputField = useRef(null)
+ const [showCopiedTooltip, setShowCopiedTooltip] = useState(false)
+
+ const copyToClipboard = (content: string) => {
+ navigator.clipboard.writeText(content).then(() => {
+ setShowCopiedTooltip(true)
+ setTimeout(() => { setShowCopiedTooltip(false) }, 2000)
+ }).catch(() => {
+ console.error("couldn't copy")
+ })
+ }
+
+ return (
+
+
+ {(props) => (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/landing/layout/footer/external-link.tsx b/src/components/links/external-link.tsx
similarity index 78%
rename from src/components/landing/layout/footer/external-link.tsx
rename to src/components/links/external-link.tsx
index aefe62dc3..16bb0b730 100644
--- a/src/components/landing/layout/footer/external-link.tsx
+++ b/src/components/links/external-link.tsx
@@ -1,19 +1,20 @@
import React, { Fragment } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
-import { IconProp } from '../../../../utils/iconProp'
+import { IconProp } from '../../utils/iconProp'
export interface ExternalLinkProp {
href: string;
text: string;
icon?: IconProp;
+ className?: string
}
-export const ExternalLink: React.FC = ({ href, text, icon }) => {
+export const ExternalLink: React.FC = ({ href, text, icon, className = 'text-light' }) => {
return (
+ className={className}>
{
icon
?
diff --git a/src/components/links/translated-external-link.tsx b/src/components/links/translated-external-link.tsx
new file mode 100644
index 000000000..efd39d697
--- /dev/null
+++ b/src/components/links/translated-external-link.tsx
@@ -0,0 +1,20 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { IconProp } from '../../utils/iconProp'
+import { ExternalLink } from './external-link'
+
+export interface TranslatedLinkProps {
+ i18nKey: string;
+ href: string;
+ icon?: IconProp;
+ className?: string
+}
+
+const TranslatedExternalLink: React.FC = ({ i18nKey, ...props }) => {
+ const { t } = useTranslation()
+ return (
+
+ )
+}
+
+export { TranslatedExternalLink }
diff --git a/src/initializers/fontAwesome.ts b/src/initializers/fontAwesome.ts
index 7f6dcfe06..57bf7b279 100644
--- a/src/initializers/fontAwesome.ts
+++ b/src/initializers/fontAwesome.ts
@@ -6,6 +6,7 @@ import {
faClock,
faCloudDownloadAlt,
faComment,
+ faCopy,
faDownload,
faFileAlt,
faGlobe,
@@ -37,5 +38,5 @@ export const setUpFontAwesome: () => void = () => {
library.add(faBolt, faPlus, faChartBar, faTv, faFileAlt, faCloudDownloadAlt,
faTrash, faSignOutAlt, faComment, faDiscourse, faMastodon, faGlobe,
faThumbtack, faClock, faTimes, faGithub, faGitlab, faGoogle, faFacebook,
- faDropbox, faTwitter, faUsers, faAddressCard, faSort, faDownload, faUpload, faTrash, faSync, faSortUp, faSortDown)
+ faDropbox, faTwitter, faUsers, faAddressCard, faSort, faDownload, faUpload, faTrash, faSync, faSortUp, faSortDown, faCopy)
}
diff --git a/src/redux/backend-config/reducers.ts b/src/redux/backend-config/reducers.ts
index 463b35487..c54a83524 100644
--- a/src/redux/backend-config/reducers.ts
+++ b/src/redux/backend-config/reducers.ts
@@ -25,6 +25,11 @@ export const initialState: BackendConfigState = {
privacy: '',
termsOfUse: '',
imprint: ''
+ },
+ version: {
+ version: '',
+ sourceCodeUrl: '',
+ issueTrackerUrl: ''
}
}
diff --git a/src/redux/backend-config/types.ts b/src/redux/backend-config/types.ts
index 04bd92cbd..10842f91e 100644
--- a/src/redux/backend-config/types.ts
+++ b/src/redux/backend-config/types.ts
@@ -3,43 +3,50 @@ import { Action } from 'redux'
export const SET_BACKEND_CONFIG_ACTION_TYPE = 'backend-config/set'
export interface BackendConfigState {
- allowAnonymous: boolean,
- authProviders: AuthProvidersState,
- customAuthNames: CustomAuthNames,
- specialLinks: SpecialLinks,
+ allowAnonymous: boolean,
+ authProviders: AuthProvidersState,
+ customAuthNames: CustomAuthNames,
+ specialLinks: SpecialLinks,
+ version: BackendVersion,
+}
+
+export interface BackendVersion {
+ version: string,
+ sourceCodeUrl: string
+ issueTrackerUrl: string
}
export interface AuthProvidersState {
- facebook: boolean,
- github: boolean,
- twitter: boolean,
- gitlab: boolean,
- dropbox: boolean,
- ldap: boolean,
- google: boolean,
- saml: boolean,
- oauth2: boolean,
- email: boolean,
- openid: boolean,
+ facebook: boolean,
+ github: boolean,
+ twitter: boolean,
+ gitlab: boolean,
+ dropbox: boolean,
+ ldap: boolean,
+ google: boolean,
+ saml: boolean,
+ oauth2: boolean,
+ email: boolean,
+ openid: boolean,
}
export interface CustomAuthNames {
- ldap: string;
- oauth2: string;
- saml: string;
+ ldap: string;
+ oauth2: string;
+ saml: string;
}
export interface SpecialLinks {
- privacy: string,
- termsOfUse: string,
- imprint: string,
+ privacy: string,
+ termsOfUse: string,
+ imprint: string,
}
export interface SetBackendConfigAction extends Action {
- type: string;
- payload: {
- state: BackendConfigState;
- };
+ type: string;
+ payload: {
+ state: BackendConfigState;
+ };
}
export type BackendConfigActions = SetBackendConfigAction;
diff --git a/src/version.json b/src/version.json
new file mode 100644
index 000000000..557c4184a
--- /dev/null
+++ b/src/version.json
@@ -0,0 +1,5 @@
+{
+ "version": "0.0",
+ "sourceCodeUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
+ "issueTrackerUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
+}