From d0fc96b929fd2cfded756ec7dda8d0c864d8460e Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Wed, 29 Jul 2020 22:58:01 +0200 Subject: [PATCH] rework how the frontend is started (#361) renamed frontend-config to api-url renamed backend-config to config removed api call to set frontend-config as the frontend either know where the backend is as it is delivered by it or get's this information via the enviroment variable REACT_APP_BACKEND always start the client on Port 3001 as the backend will run on 3000 during development. changed the port on multiple occasions to accommodate for this added package.json script 'start:dev' changed README to better explain how to run backend and frontend side-by-side --- README.md | 8 +++-- cypress.json | 2 +- cypress/support/config.ts | 2 +- package.json | 7 ++-- public/api/v2/config | 2 +- public/config.json | 3 -- src/api/auth.ts | 8 ++--- src/api/backend-config/index.ts | 8 ----- src/api/config/index.ts | 11 ++++++ src/api/{backend-config => config}/types.ts | 2 +- src/api/frontend-config/index.ts | 8 ----- src/api/frontend-config/types.ts | 3 -- src/api/history.ts | 12 +++---- src/api/imageProxy.ts | 4 +-- src/api/me.ts | 8 ++--- src/api/note.ts | 6 ++-- .../application-loader/application-loader.tsx | 3 +- .../initializers/configLoader.ts | 25 ++++++------- src/components/common/branding/branding.tsx | 2 +- .../common/document-title/document-title.tsx | 2 +- .../replace-components/image/image-frame.tsx | 2 +- .../layout/footer/powered-by-links.tsx | 2 +- .../layout/navigation/sign-in-button.tsx | 2 +- .../layout/version-info/version-info.tsx | 2 +- .../intro/cover-buttons/cover-buttons.tsx | 2 +- .../landing/pages/login/auth/via-ldap.tsx | 2 +- .../pages/login/auth/via-one-click.tsx | 35 +++++++++++-------- src/components/landing/pages/login/login.tsx | 4 +-- .../settings/profile-account-management.tsx | 4 +-- src/redux/api-url/methods.ts | 10 ++++++ src/redux/api-url/reducers.ts | 15 ++++++++ src/redux/api-url/types.ts | 17 +++++++++ src/redux/backend-config/methods.ts | 11 ------ src/redux/backend-config/types.ts | 14 -------- src/redux/config/methods.ts | 11 ++++++ .../{backend-config => config}/reducers.ts | 12 +++---- src/redux/config/types.ts | 14 ++++++++ src/redux/frontend-config/methods.ts | 14 -------- src/redux/frontend-config/reducers.ts | 16 --------- src/redux/frontend-config/types.ts | 14 -------- src/redux/index.ts | 22 ++++++------ src/utils/apiUtils.ts | 4 +-- 42 files changed, 173 insertions(+), 182 deletions(-) delete mode 100644 public/config.json delete mode 100644 src/api/backend-config/index.ts create mode 100644 src/api/config/index.ts rename src/api/{backend-config => config}/types.ts (96%) delete mode 100644 src/api/frontend-config/index.ts delete mode 100644 src/api/frontend-config/types.ts create mode 100644 src/redux/api-url/methods.ts create mode 100644 src/redux/api-url/reducers.ts create mode 100644 src/redux/api-url/types.ts delete mode 100644 src/redux/backend-config/methods.ts delete mode 100644 src/redux/backend-config/types.ts create mode 100644 src/redux/config/methods.ts rename src/redux/{backend-config => config}/reducers.ts (59%) create mode 100644 src/redux/config/types.ts delete mode 100644 src/redux/frontend-config/methods.ts delete mode 100644 src/redux/frontend-config/reducers.ts delete mode 100644 src/redux/frontend-config/types.ts diff --git a/README.md b/README.md index 9a1c3f2bc..4ab46ba56 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,11 @@ You'll need at least Node 10 (we recommend 12). We use [yarn](https://yarnpkg.co 1. Clone this repo (e.g. `git clone https://github.com/codimd/react-client.git codimd-react-client`) 2. Go inside the repo (e.g. `cd codimd-react-client`) 3. run `yarn install` -4. run `yarn start` +4. Either run + - `yarn start:dev` (expects [a server](https://github.com/codimd/server/tree/develop) running under [http://localhost:3000](http://localhost:3000)) + - `yarn start` (makes all api calls to the same domain the react-client runs on (normally [http://localhost:3001](http://localhost:3001) )) -This should run the app in the development mode and open [http://localhost:3000](http://localhost:3000) in your browser. +This should run the app in the development mode and open [http://localhost:3001](http://localhost:3001) in your browser. The page will reload if you make edits. You will also see any lint errors in the console. @@ -26,7 +28,7 @@ You will also see any lint errors in the console. Unit testing is done via jest. -1. `yarn test` +1. run `yarn test` #### End2End diff --git a/cypress.json b/cypress.json index 5993cb871..f070aa584 100644 --- a/cypress.json +++ b/cypress.json @@ -1,5 +1,5 @@ { - "baseUrl": "http://localhost:3000/", + "baseUrl": "http://localhost:3001/", "defaultCommandTimeout": 15000, "experimentalFetchPolyfill": true } diff --git a/cypress/support/config.ts b/cypress/support/config.ts index c9dbbacfd..b92e7b357 100644 --- a/cypress/support/config.ts +++ b/cypress/support/config.ts @@ -5,7 +5,7 @@ export const banner = { export const branding = { name: 'ACME Corp', - logo: 'http://localhost:3000/acme.png' + logo: 'http://localhost:3001/acme.png' } beforeEach(() => { diff --git a/package.json b/package.json index 90656c7b8..c529632aa 100644 --- a/package.json +++ b/package.json @@ -85,15 +85,16 @@ "use-resize-observer": "6.1.0" }, "scripts": { - "start": "react-scripts start", + "start": "PORT=3001 react-scripts start", + "start:dev": "REACT_APP_BACKEND=http://localhost:3000 yarn start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "cy:open": "cypress open", "cy:run:chrome": "cypress run --browser chrome", "cy:run:firefox": "cypress run --browser firefox", - "e2e:chrome": "start-server-and-test start http-get://localhost:3000 cy:run:chrome", - "e2e:firefox": "start-server-and-test start http-get://localhost:3000 cy:run:firefox" + "e2e:chrome": "start-server-and-test start http-get://localhost:3001 cy:run:chrome", + "e2e:firefox": "start-server-and-test start http-get://localhost:3001 cy:run:firefox" }, "eslintConfig": { "parserOptions": { diff --git a/public/api/v2/config b/public/api/v2/config index ba74eae9c..30ab2aa80 100644 --- a/public/api/v2/config +++ b/public/api/v2/config @@ -15,7 +15,7 @@ }, "branding": { "name": "ACME Corp", - "logo": "http://localhost:3000/acme.png" + "logo": "http://localhost:3001/acme.png" }, "banner": { "text": "This is the test banner text", diff --git a/public/config.json b/public/config.json deleted file mode 100644 index c2b272d3b..000000000 --- a/public/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "backendUrl": "http://localhost:3000" -} diff --git a/src/api/auth.ts b/src/api/auth.ts index 87f1a890b..538ab8c9c 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -1,8 +1,8 @@ -import { expectResponseCode, getBackendUrl } from '../utils/apiUtils' +import { expectResponseCode, getApiUrl } from '../utils/apiUtils' import { defaultFetchConfig } from './default' export const doEmailLogin = async (email: string, password: string): Promise => { - const response = await fetch(getBackendUrl() + '/auth/email', { + const response = await fetch(getApiUrl() + '/auth/email', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ @@ -15,7 +15,7 @@ export const doEmailLogin = async (email: string, password: string): Promise => { - const response = await fetch(getBackendUrl() + '/auth/ldap', { + const response = await fetch(getApiUrl() + '/auth/ldap', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ @@ -28,7 +28,7 @@ export const doLdapLogin = async (username: string, password: string): Promise => { - const response = await fetch(getBackendUrl() + '/auth/openid', { + const response = await fetch(getApiUrl() + '/auth/openid', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ diff --git a/src/api/backend-config/index.ts b/src/api/backend-config/index.ts deleted file mode 100644 index c368aab66..000000000 --- a/src/api/backend-config/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expectResponseCode, getBackendUrl } from '../../utils/apiUtils' -import { BackendConfig } from './types' - -export const getBackendConfig = async (): Promise => { - const response = await fetch(getBackendUrl() + '/config') - expectResponseCode(response) - return await response.json() as Promise -} diff --git a/src/api/config/index.ts b/src/api/config/index.ts new file mode 100644 index 000000000..c4878dcfc --- /dev/null +++ b/src/api/config/index.ts @@ -0,0 +1,11 @@ +import { expectResponseCode, getApiUrl } from '../../utils/apiUtils' +import { defaultFetchConfig } from '../default' +import { Config } from './types' + +export const getConfig = async (): Promise => { + const response = await fetch(getApiUrl() + '/config', { + ...defaultFetchConfig + }) + expectResponseCode(response) + return await response.json() as Promise +} diff --git a/src/api/backend-config/types.ts b/src/api/config/types.ts similarity index 96% rename from src/api/backend-config/types.ts rename to src/api/config/types.ts index 77c299214..f69a53c99 100644 --- a/src/api/backend-config/types.ts +++ b/src/api/config/types.ts @@ -1,4 +1,4 @@ -export interface BackendConfig { +export interface Config { allowAnonymous: boolean, authProviders: AuthProvidersState, branding: BrandingConfig, diff --git a/src/api/frontend-config/index.ts b/src/api/frontend-config/index.ts deleted file mode 100644 index d7c6df8af..000000000 --- a/src/api/frontend-config/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expectResponseCode } from '../../utils/apiUtils' -import { FrontendConfig } from './types' - -export const getFrontendConfig = async (baseUrl: string): Promise => { - const response = await fetch(`${baseUrl}config.json`) - expectResponseCode(response) - return await response.json() as Promise -} diff --git a/src/api/frontend-config/types.ts b/src/api/frontend-config/types.ts deleted file mode 100644 index 12fb48058..000000000 --- a/src/api/frontend-config/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface FrontendConfig { - backendUrl: string -} diff --git a/src/api/history.ts b/src/api/history.ts index 765b020c6..6acaa3874 100644 --- a/src/api/history.ts +++ b/src/api/history.ts @@ -1,15 +1,15 @@ import { HistoryEntry } from '../components/landing/pages/history/history' -import { expectResponseCode, getBackendUrl } from '../utils/apiUtils' +import { expectResponseCode, getApiUrl } from '../utils/apiUtils' import { defaultFetchConfig } from './default' export const getHistory = async (): Promise => { - const response = await fetch(getBackendUrl() + '/history') + const response = await fetch(getApiUrl() + '/history') expectResponseCode(response) return await response.json() as Promise } export const setHistory = async (entries: HistoryEntry[]): Promise => { - const response = await fetch(getBackendUrl() + '/history', { + const response = await fetch(getApiUrl() + '/history', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ @@ -20,7 +20,7 @@ export const setHistory = async (entries: HistoryEntry[]): Promise => { } export const deleteHistory = async (): Promise => { - const response = await fetch(getBackendUrl() + '/history', { + const response = await fetch(getApiUrl() + '/history', { ...defaultFetchConfig, method: 'DELETE' }) @@ -28,7 +28,7 @@ export const deleteHistory = async (): Promise => { } export const updateHistoryEntry = async (noteId: string, entry: HistoryEntry): Promise => { - const response = await fetch(getBackendUrl() + '/history/' + noteId, { + const response = await fetch(getApiUrl() + '/history/' + noteId, { ...defaultFetchConfig, method: 'PUT', body: JSON.stringify(entry) @@ -38,7 +38,7 @@ export const updateHistoryEntry = async (noteId: string, entry: HistoryEntry): P } export const deleteHistoryEntry = async (noteId: string): Promise => { - const response = await fetch(getBackendUrl() + '/history/' + noteId, { + const response = await fetch(getApiUrl() + '/history/' + noteId, { ...defaultFetchConfig, method: 'DELETE' }) diff --git a/src/api/imageProxy.ts b/src/api/imageProxy.ts index c80a27246..042235093 100644 --- a/src/api/imageProxy.ts +++ b/src/api/imageProxy.ts @@ -1,9 +1,9 @@ import { ImageProxyResponse } from '../components/editor/markdown-renderer/replace-components/image/types' -import { expectResponseCode, getBackendUrl } from '../utils/apiUtils' +import { expectResponseCode, getApiUrl } from '../utils/apiUtils' import { defaultFetchConfig } from './default' export const getProxiedUrl = async (imageUrl: string): Promise => { - const response = await fetch(getBackendUrl() + '/media/proxy', { + const response = await fetch(getApiUrl() + '/media/proxy', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ diff --git a/src/api/me.ts b/src/api/me.ts index fa8cb8c4f..5cf5ac25e 100644 --- a/src/api/me.ts +++ b/src/api/me.ts @@ -1,5 +1,5 @@ import { LoginProvider } from '../redux/user/types' -import { expectResponseCode, getBackendUrl } from '../utils/apiUtils' +import { expectResponseCode, getApiUrl } from '../utils/apiUtils' import { defaultFetchConfig } from './default' export const getMe = async (): Promise => { @@ -16,7 +16,7 @@ export interface meResponse { } export const updateDisplayName = async (displayName: string): Promise => { - const response = await fetch(getBackendUrl() + '/me', { + const response = await fetch(getApiUrl() + '/me', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ @@ -28,7 +28,7 @@ export const updateDisplayName = async (displayName: string): Promise => { } export const changePassword = async (oldPassword: string, newPassword: string): Promise => { - const response = await fetch(getBackendUrl() + '/me/password', { + const response = await fetch(getApiUrl() + '/me/password', { ...defaultFetchConfig, method: 'POST', body: JSON.stringify({ @@ -41,7 +41,7 @@ export const changePassword = async (oldPassword: string, newPassword: string): } export const deleteUser = async (): Promise => { - const response = await fetch(getBackendUrl() + '/me', { + const response = await fetch(getApiUrl() + '/me', { ...defaultFetchConfig, method: 'DELETE' }) diff --git a/src/api/note.ts b/src/api/note.ts index a399e6b53..761789a99 100644 --- a/src/api/note.ts +++ b/src/api/note.ts @@ -1,4 +1,4 @@ -import { expectResponseCode, getBackendUrl } from '../utils/apiUtils' +import { expectResponseCode, getApiUrl } from '../utils/apiUtils' import { defaultFetchConfig } from './default' interface LastChange { @@ -19,13 +19,13 @@ export interface Note { } export const getNote = async (noteId: string): Promise => { - const response = await fetch(getBackendUrl() + `/notes/${noteId}`) + const response = await fetch(getApiUrl() + `/notes/${noteId}`) expectResponseCode(response) return await response.json() as Promise } export const deleteNote = async (noteId: string): Promise => { - const response = await fetch(getBackendUrl() + `/notes/${noteId}`, { + const response = await fetch(getApiUrl() + `/notes/${noteId}`, { ...defaultFetchConfig, method: 'DELETE' }) diff --git a/src/components/application-loader/application-loader.tsx b/src/components/application-loader/application-loader.tsx index 47c6ba47d..16f8bd07e 100644 --- a/src/components/application-loader/application-loader.tsx +++ b/src/components/application-loader/application-loader.tsx @@ -9,8 +9,7 @@ export const ApplicationLoader: React.FC = ({ children }) => { const { pathname } = useLocation() const setUpTasks = useCallback(() => { - const baseUrl: string = window.location.pathname.replace(pathname, '') + '/' - console.debug('Base URL is', baseUrl) + const baseUrl: string = window.location.pathname.replace(pathname, '') return createSetUpTaskList(baseUrl) }, [pathname]) diff --git a/src/components/application-loader/initializers/configLoader.ts b/src/components/application-loader/initializers/configLoader.ts index 13cf0ef7d..b7fcc3923 100644 --- a/src/components/application-loader/initializers/configLoader.ts +++ b/src/components/application-loader/initializers/configLoader.ts @@ -1,24 +1,21 @@ -import { getBackendConfig } from '../../../api/backend-config' -import { getFrontendConfig } from '../../../api/frontend-config' -import { setBackendConfig } from '../../../redux/backend-config/methods' +import { getConfig } from '../../../api/config' +import { setApiUrl } from '../../../redux/api-url/methods' import { setBanner } from '../../../redux/banner/methods' -import { setFrontendConfig } from '../../../redux/frontend-config/methods' +import { setConfig } from '../../../redux/config/methods' import { getAndSetUser } from '../../../utils/apiUtils' export const loadAllConfig: (baseUrl: string) => Promise = async (baseUrl) => { - const frontendConfig = await getFrontendConfig(baseUrl) - if (!frontendConfig) { - return Promise.reject(new Error('Frontend config empty!')) - } - setFrontendConfig(frontendConfig) + setApiUrl({ + apiUrl: (process.env.REACT_APP_BACKEND || baseUrl) + '/api/v2' + }) - const backendConfig = await getBackendConfig() - if (!backendConfig) { - return Promise.reject(new Error('Backend config empty!')) + const config = await getConfig() + if (!config) { + return Promise.reject(new Error('Config empty!')) } - setBackendConfig(backendConfig) + setConfig(config) - const banner = backendConfig.banner + const banner = config.banner if (banner.text !== '') { const lastAcknowledgedTimestamp = window.localStorage.getItem('bannerTimeStamp') || '' setBanner({ diff --git a/src/components/common/branding/branding.tsx b/src/components/common/branding/branding.tsx index 5f8de4fe9..7829800ee 100644 --- a/src/components/common/branding/branding.tsx +++ b/src/components/common/branding/branding.tsx @@ -9,7 +9,7 @@ export interface BrandingProps { } export const Branding: React.FC = ({ inline = false }) => { - const branding = useSelector((state: ApplicationState) => state.backendConfig.branding) + const branding = useSelector((state: ApplicationState) => state.config.branding) const showBranding = !!branding.name || !!branding.logo return ( diff --git a/src/components/common/document-title/document-title.tsx b/src/components/common/document-title/document-title.tsx index 16399227f..41d777900 100644 --- a/src/components/common/document-title/document-title.tsx +++ b/src/components/common/document-title/document-title.tsx @@ -7,7 +7,7 @@ export interface DocumentTitleProps { } export const DocumentTitle: React.FC = ({ title }) => { - const branding = useSelector((state: ApplicationState) => state.backendConfig.branding) + const branding = useSelector((state: ApplicationState) => state.config.branding) useEffect(() => { document.title = `${title ? title + ' - ' : ''}CodiMD ${branding.name ? ` @ ${branding.name}` : ''}` diff --git a/src/components/editor/markdown-renderer/replace-components/image/image-frame.tsx b/src/components/editor/markdown-renderer/replace-components/image/image-frame.tsx index 02d2830ad..4421ae9ea 100644 --- a/src/components/editor/markdown-renderer/replace-components/image/image-frame.tsx +++ b/src/components/editor/markdown-renderer/replace-components/image/image-frame.tsx @@ -5,7 +5,7 @@ import { ApplicationState } from '../../../../../redux' export const ImageFrame: React.FC> = ({ alt, src, ...props }) => { const [imageUrl, setImageUrl] = useState('') - const imageProxyEnabled = useSelector((state: ApplicationState) => state.backendConfig.useImageProxy) + const imageProxyEnabled = useSelector((state: ApplicationState) => state.config.useImageProxy) useEffect(() => { if (!imageProxyEnabled || !src) { diff --git a/src/components/landing/layout/footer/powered-by-links.tsx b/src/components/landing/layout/footer/powered-by-links.tsx index 9e2baed7f..b6038dfb7 100644 --- a/src/components/landing/layout/footer/powered-by-links.tsx +++ b/src/components/landing/layout/footer/powered-by-links.tsx @@ -10,7 +10,7 @@ import { VersionInfo } from '../version-info/version-info' export const PoweredByLinks: React.FC = () => { useTranslation() - const config = useSelector((state: ApplicationState) => state.backendConfig) + const config = useSelector((state: ApplicationState) => state.config) return (

diff --git a/src/components/landing/layout/navigation/sign-in-button.tsx b/src/components/landing/layout/navigation/sign-in-button.tsx index 084ae6996..53ec2778f 100644 --- a/src/components/landing/layout/navigation/sign-in-button.tsx +++ b/src/components/landing/layout/navigation/sign-in-button.tsx @@ -13,7 +13,7 @@ type SignInButtonProps = { export const SignInButton: React.FC = ({ variant, ...props }) => { const { t } = useTranslation() - const authProviders = useSelector((state: ApplicationState) => state.backendConfig.authProviders) + const authProviders = useSelector((state: ApplicationState) => state.config.authProviders) return ( diff --git a/src/components/landing/layout/version-info/version-info.tsx b/src/components/landing/layout/version-info/version-info.tsx index 4d6f94167..990b5939b 100644 --- a/src/components/landing/layout/version-info/version-info.tsx +++ b/src/components/landing/layout/version-info/version-info.tsx @@ -17,7 +17,7 @@ export const VersionInfo: React.FC = () => { const { t } = useTranslation() - const serverVersion = useSelector((state: ApplicationState) => state.backendConfig.version) + const serverVersion = useSelector((state: ApplicationState) => state.config.version) const column = (title: string, version: string, sourceCodeLink: string, issueTrackerLink: string) => ( diff --git a/src/components/landing/pages/intro/cover-buttons/cover-buttons.tsx b/src/components/landing/pages/intro/cover-buttons/cover-buttons.tsx index cc9e7cc94..e3c640cd9 100644 --- a/src/components/landing/pages/intro/cover-buttons/cover-buttons.tsx +++ b/src/components/landing/pages/intro/cover-buttons/cover-buttons.tsx @@ -11,7 +11,7 @@ import './cover-buttons.scss' export const CoverButtons: React.FC = () => { useTranslation() const user = useSelector((state: ApplicationState) => state.user) - const authProviders = useSelector((state: ApplicationState) => state.backendConfig.authProviders) + const authProviders = useSelector((state: ApplicationState) => state.config.authProviders) if (user) { return null diff --git a/src/components/landing/pages/login/auth/via-ldap.tsx b/src/components/landing/pages/login/auth/via-ldap.tsx index aa36c0892..1ea19f4c4 100644 --- a/src/components/landing/pages/login/auth/via-ldap.tsx +++ b/src/components/landing/pages/login/auth/via-ldap.tsx @@ -9,7 +9,7 @@ import { getAndSetUser } from '../../../../../utils/apiUtils' export const ViaLdap: React.FC = () => { const { t } = useTranslation() - const ldapCustomName = useSelector((state: ApplicationState) => state.backendConfig.customAuthNames.ldap) + const ldapCustomName = useSelector((state: ApplicationState) => state.config.customAuthNames.ldap) const [username, setUsername] = useState('') const [password, setPassword] = useState('') diff --git a/src/components/landing/pages/login/auth/via-one-click.tsx b/src/components/landing/pages/login/auth/via-one-click.tsx index 35cc4f4fe..e2bb4f399 100644 --- a/src/components/landing/pages/login/auth/via-one-click.tsx +++ b/src/components/landing/pages/login/auth/via-one-click.tsx @@ -1,4 +1,6 @@ import React from 'react' +import { useSelector } from 'react-redux' +import { ApplicationState } from '../../../../../redux' import { IconName } from '../../../../common/fork-awesome/fork-awesome-icon' import { SocialLinkButton } from './social-link-button/social-link-button' @@ -13,74 +15,75 @@ export enum OneClickType { 'TWITTER' = 'twitter' } -type OneClick2Map = (oneClickType: OneClickType) => { +interface OneClickMetadata { name: string, icon: IconName, className: string, url: string -}; - -const buildBackendAuthUrl = (backendName: string) => { - return `https://localhost:3000/auth/${backendName}` } -const getMetadata: OneClick2Map = (oneClickType: OneClickType) => { +const buildBackendAuthUrl = (backendUrl: string, backendName: string): string => { + return `${backendUrl}/auth/${backendName}` +} + +const getMetadata = (backendUrl: string, oneClickType: OneClickType): OneClickMetadata => { + const buildBackendAuthUrlWithFirstParameterSet = (backendName: string): string => buildBackendAuthUrl(backendUrl, backendName) switch (oneClickType) { case OneClickType.DROPBOX: return { name: 'Dropbox', icon: 'dropbox', className: 'btn-social-dropbox', - url: buildBackendAuthUrl('dropbox') + url: buildBackendAuthUrlWithFirstParameterSet('dropbox') } case OneClickType.FACEBOOK: return { name: 'Facebook', icon: 'facebook', className: 'btn-social-facebook', - url: buildBackendAuthUrl('facebook') + url: buildBackendAuthUrlWithFirstParameterSet('facebook') } case OneClickType.GITHUB: return { name: 'GitHub', icon: 'github', className: 'btn-social-github', - url: buildBackendAuthUrl('github') + url: buildBackendAuthUrlWithFirstParameterSet('github') } case OneClickType.GITLAB: return { name: 'GitLab', icon: 'gitlab', className: 'btn-social-gitlab', - url: buildBackendAuthUrl('gitlab') + url: buildBackendAuthUrlWithFirstParameterSet('gitlab') } case OneClickType.GOOGLE: return { name: 'Google', icon: 'google', className: 'btn-social-google', - url: buildBackendAuthUrl('google') + url: buildBackendAuthUrlWithFirstParameterSet('google') } case OneClickType.OAUTH2: return { name: 'OAuth2', icon: 'address-card', className: 'btn-primary', - url: buildBackendAuthUrl('oauth2') + url: buildBackendAuthUrlWithFirstParameterSet('oauth2') } case OneClickType.SAML: return { name: 'SAML', icon: 'users', className: 'btn-success', - url: buildBackendAuthUrl('saml') + url: buildBackendAuthUrlWithFirstParameterSet('saml') } case OneClickType.TWITTER: return { name: 'Twitter', icon: 'twitter', className: 'btn-social-twitter', - url: buildBackendAuthUrl('twitter') + url: buildBackendAuthUrlWithFirstParameterSet('twitter') } default: return { @@ -98,8 +101,10 @@ export interface ViaOneClickProps { } const ViaOneClick: React.FC = ({ oneClickType, optionalName }) => { - const { name, icon, className, url } = getMetadata(oneClickType) + const backendUrl = useSelector((state: ApplicationState) => state.apiUrl.apiUrl) + const { name, icon, className, url } = getMetadata(backendUrl, oneClickType) const text = optionalName || name + return ( { useTranslation() - const authProviders = useSelector((state: ApplicationState) => state.backendConfig.authProviders) - const customAuthNames = useSelector((state: ApplicationState) => state.backendConfig.customAuthNames) + const authProviders = useSelector((state: ApplicationState) => state.config.authProviders) + const customAuthNames = useSelector((state: ApplicationState) => state.config.customAuthNames) const userLoginState = useSelector((state: ApplicationState) => state.user) const oneClickProviders = [authProviders.dropbox, authProviders.facebook, authProviders.github, authProviders.gitlab, diff --git a/src/components/landing/pages/profile/settings/profile-account-management.tsx b/src/components/landing/pages/profile/settings/profile-account-management.tsx index b38298511..a0dd1c37c 100644 --- a/src/components/landing/pages/profile/settings/profile-account-management.tsx +++ b/src/components/landing/pages/profile/settings/profile-account-management.tsx @@ -3,7 +3,7 @@ import { Button, Card, Modal } from 'react-bootstrap' import { Trans, useTranslation } from 'react-i18next' import { deleteUser } from '../../../../../api/me' import { clearUser } from '../../../../../redux/user/methods' -import { getBackendUrl } from '../../../../../utils/apiUtils' +import { getApiUrl } from '../../../../../utils/apiUtils' import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon' export const ProfileAccountManagement: React.FC = () => { @@ -57,7 +57,7 @@ export const ProfileAccountManagement: React.FC = () => { - diff --git a/src/redux/api-url/methods.ts b/src/redux/api-url/methods.ts new file mode 100644 index 000000000..47fbf6ccd --- /dev/null +++ b/src/redux/api-url/methods.ts @@ -0,0 +1,10 @@ +import { store } from '../../utils/store' +import { ApiUrlActionType, ApiUrlObject, SetApiUrlAction } from './types' + +export const setApiUrl = (state: ApiUrlObject): void => { + const action: SetApiUrlAction = { + type: ApiUrlActionType.SET_API_URL, + state + } + store.dispatch(action) +} diff --git a/src/redux/api-url/reducers.ts b/src/redux/api-url/reducers.ts new file mode 100644 index 000000000..59e277a3a --- /dev/null +++ b/src/redux/api-url/reducers.ts @@ -0,0 +1,15 @@ +import { Reducer } from 'redux' +import { ApiUrlActions, ApiUrlActionType, ApiUrlObject, SetApiUrlAction } from './types' + +export const initialState: ApiUrlObject = { + apiUrl: '' +} + +export const ApiUrlReducer: Reducer = (state: ApiUrlObject = initialState, action: ApiUrlActions) => { + switch (action.type) { + case ApiUrlActionType.SET_API_URL: + return (action as SetApiUrlAction).state + default: + return state + } +} diff --git a/src/redux/api-url/types.ts b/src/redux/api-url/types.ts new file mode 100644 index 000000000..6757d7e29 --- /dev/null +++ b/src/redux/api-url/types.ts @@ -0,0 +1,17 @@ +import { Action } from 'redux' + +export enum ApiUrlActionType { + SET_API_URL = 'api-url/set' +} + +export interface ApiUrlActions extends Action { + type: ApiUrlActionType; +} + +export interface SetApiUrlAction extends ApiUrlActions { + state: ApiUrlObject; +} + +export interface ApiUrlObject { + apiUrl: string +} diff --git a/src/redux/backend-config/methods.ts b/src/redux/backend-config/methods.ts deleted file mode 100644 index b6e00697c..000000000 --- a/src/redux/backend-config/methods.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BackendConfig } from '../../api/backend-config/types' -import { store } from '../../utils/store' -import { BackendConfigActionType, SetBackendConfigAction } from './types' - -export const setBackendConfig = (state: BackendConfig): void => { - const action: SetBackendConfigAction = { - type: BackendConfigActionType.SET_BACKEND_CONFIG, - state: state - } - store.dispatch(action) -} diff --git a/src/redux/backend-config/types.ts b/src/redux/backend-config/types.ts deleted file mode 100644 index 689ea51d5..000000000 --- a/src/redux/backend-config/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Action } from 'redux' -import { BackendConfig } from '../../api/backend-config/types' - -export enum BackendConfigActionType { - SET_BACKEND_CONFIG = 'backend-config/set' -} - -export interface BackendConfigActions extends Action{ - type: BackendConfigActionType; -} - -export interface SetBackendConfigAction extends BackendConfigActions { - state: BackendConfig; -} diff --git a/src/redux/config/methods.ts b/src/redux/config/methods.ts new file mode 100644 index 000000000..29298280c --- /dev/null +++ b/src/redux/config/methods.ts @@ -0,0 +1,11 @@ +import { Config } from '../../api/config/types' +import { store } from '../../utils/store' +import { ConfigActionType, SetConfigAction } from './types' + +export const setConfig = (state: Config): void => { + const action: SetConfigAction = { + type: ConfigActionType.SET_CONFIG, + state: state + } + store.dispatch(action) +} diff --git a/src/redux/backend-config/reducers.ts b/src/redux/config/reducers.ts similarity index 59% rename from src/redux/backend-config/reducers.ts rename to src/redux/config/reducers.ts index 90b916169..82eb94e90 100644 --- a/src/redux/backend-config/reducers.ts +++ b/src/redux/config/reducers.ts @@ -1,8 +1,8 @@ import { Reducer } from 'redux' -import { BackendConfig } from '../../api/backend-config/types' -import { BackendConfigActions, BackendConfigActionType, SetBackendConfigAction } from './types' +import { Config } from '../../api/config/types' +import { ConfigActions, ConfigActionType, SetConfigAction } from './types' -export const initialState: BackendConfig = { +export const initialState: Config = { allowAnonymous: true, authProviders: { facebook: false, @@ -43,10 +43,10 @@ export const initialState: BackendConfig = { } } -export const BackendConfigReducer: Reducer<(BackendConfig), BackendConfigActions> = (state: (BackendConfig) = initialState, action: BackendConfigActions) => { +export const ConfigReducer: Reducer = (state: Config = initialState, action: ConfigActions) => { switch (action.type) { - case BackendConfigActionType.SET_BACKEND_CONFIG: - return (action as SetBackendConfigAction).state + case ConfigActionType.SET_CONFIG: + return (action as SetConfigAction).state default: return state } diff --git a/src/redux/config/types.ts b/src/redux/config/types.ts new file mode 100644 index 000000000..5decd6053 --- /dev/null +++ b/src/redux/config/types.ts @@ -0,0 +1,14 @@ +import { Action } from 'redux' +import { Config } from '../../api/config/types' + +export enum ConfigActionType { + SET_CONFIG = 'config/set' +} + +export interface ConfigActions extends Action { + type: ConfigActionType; +} + +export interface SetConfigAction extends ConfigActions { + state: Config; +} diff --git a/src/redux/frontend-config/methods.ts b/src/redux/frontend-config/methods.ts deleted file mode 100644 index 787d36bed..000000000 --- a/src/redux/frontend-config/methods.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FrontendConfig } from '../../api/frontend-config/types' -import { store } from '../../utils/store' -import { FrontendConfigActionType, SetFrontendConfigAction } from './types' - -export const setFrontendConfig = (state: FrontendConfig): void => { - const action: SetFrontendConfigAction = { - type: FrontendConfigActionType.SET_FRONTEND_CONFIG, - state: { - ...state, - backendUrl: state.backendUrl + '/api/v2' - } - } - store.dispatch(action) -} diff --git a/src/redux/frontend-config/reducers.ts b/src/redux/frontend-config/reducers.ts deleted file mode 100644 index 81e12c930..000000000 --- a/src/redux/frontend-config/reducers.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Reducer } from 'redux' -import { FrontendConfig } from '../../api/frontend-config/types' -import { FrontendConfigActions, FrontendConfigActionType, SetFrontendConfigAction } from './types' - -const initialState: FrontendConfig = { - backendUrl: '' -} - -export const FrontendConfigReducer: Reducer<(FrontendConfig), FrontendConfigActions> = (state: (FrontendConfig) = initialState, action: FrontendConfigActions) => { - switch (action.type) { - case FrontendConfigActionType.SET_FRONTEND_CONFIG: - return (action as SetFrontendConfigAction).state - default: - return state - } -} diff --git a/src/redux/frontend-config/types.ts b/src/redux/frontend-config/types.ts deleted file mode 100644 index 6343ac860..000000000 --- a/src/redux/frontend-config/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Action } from 'redux' -import { FrontendConfig } from '../../api/frontend-config/types' - -export enum FrontendConfigActionType { - SET_FRONTEND_CONFIG = 'frontend-config/set' -} - -export interface FrontendConfigActions extends Action { - type: FrontendConfigActionType; -} - -export interface SetFrontendConfigAction extends FrontendConfigActions { - state: FrontendConfig; -} diff --git a/src/redux/index.ts b/src/redux/index.ts index b6c7ce2e6..6344b98b2 100644 --- a/src/redux/index.ts +++ b/src/redux/index.ts @@ -1,27 +1,27 @@ import { combineReducers, Reducer } from 'redux' -import { BackendConfig } from '../api/backend-config/types' -import { FrontendConfig } from '../api/frontend-config/types' -import { BackendConfigReducer } from './backend-config/reducers' +import { Config } from '../api/config/types' +import { ApiUrlReducer } from './api-url/reducers' +import { ApiUrlObject } from './api-url/types' import { BannerReducer } from './banner/reducers' import { BannerState } from './banner/types' +import { ConfigReducer } from './config/reducers' import { EditorConfigReducer } from './editor/reducers' import { EditorConfig } from './editor/types' -import { FrontendConfigReducer } from './frontend-config/reducers' import { UserReducer } from './user/reducers' import { MaybeUserState } from './user/types' export interface ApplicationState { - user: MaybeUserState; - backendConfig: BackendConfig; - banner: BannerState; - frontendConfig: FrontendConfig; - editorConfig: EditorConfig; + user: MaybeUserState; + config: Config; + banner: BannerState; + apiUrl: ApiUrlObject; + editorConfig: EditorConfig; } export const allReducers: Reducer = combineReducers({ user: UserReducer, - backendConfig: BackendConfigReducer, + config: ConfigReducer, banner: BannerReducer, - frontendConfig: FrontendConfigReducer, + apiUrl: ApiUrlReducer, editorConfig: EditorConfigReducer }) diff --git a/src/utils/apiUtils.ts b/src/utils/apiUtils.ts index dff5a30b1..a41fc022e 100644 --- a/src/utils/apiUtils.ts +++ b/src/utils/apiUtils.ts @@ -12,8 +12,8 @@ export const getAndSetUser: () => (Promise) = async () => { }) } -export const getBackendUrl: (() => string) = () => { - return store.getState().frontendConfig.backendUrl +export const getApiUrl = (): string => { + return store.getState().apiUrl.apiUrl } export const expectResponseCode = (response: Response, code = 200): void => {