delete useless custombackend popup
correct load of subpage when standalone binary ability to set external videourl when using standalone binary
This commit is contained in:
		
							
								
								
									
										37
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/App.tsx
									
									
									
									
									
								
							@@ -10,7 +10,6 @@ import style from './App.module.css';
 | 
			
		||||
import SettingsPage from './pages/SettingsPage/SettingsPage';
 | 
			
		||||
import CategoryPage from './pages/CategoryPage/CategoryPage';
 | 
			
		||||
import {APINode, apiTokenValid, callApiUnsafe, refreshAPIToken} from './utils/Api';
 | 
			
		||||
import {NoBackendConnectionPopup} from './elements/Popups/NoBackendConnectionPopup/NoBackendConnectionPopup';
 | 
			
		||||
 | 
			
		||||
import {BrowserRouter as Router, NavLink, Route, Switch} from 'react-router-dom';
 | 
			
		||||
import Player from './pages/Player/Player';
 | 
			
		||||
@@ -22,7 +21,6 @@ import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage';
 | 
			
		||||
interface state {
 | 
			
		||||
    password: boolean | null; // null if uninitialized - true if pwd needed false if not needed
 | 
			
		||||
    mediacentername: string;
 | 
			
		||||
    onapierror: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -50,7 +48,6 @@ class App extends React.Component<{}, state> {
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            mediacentername: 'OpenMediaCenter',
 | 
			
		||||
            onapierror: false,
 | 
			
		||||
            password: pwdneeded
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -77,26 +74,18 @@ class App extends React.Component<{}, state> {
 | 
			
		||||
 | 
			
		||||
    initialAPICall(): void {
 | 
			
		||||
        // this is the first api call so if it fails we know there is no connection to backend
 | 
			
		||||
        callApiUnsafe(
 | 
			
		||||
            APINode.Init,
 | 
			
		||||
            {action: 'loadInitialData'},
 | 
			
		||||
            (result: SettingsTypes.initialApiCallData) => {
 | 
			
		||||
                // set theme
 | 
			
		||||
                GlobalInfos.enableDarkTheme(result.DarkMode);
 | 
			
		||||
        callApiUnsafe(APINode.Init, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => {
 | 
			
		||||
            // set theme
 | 
			
		||||
            GlobalInfos.enableDarkTheme(result.DarkMode);
 | 
			
		||||
 | 
			
		||||
                GlobalInfos.setVideoPath(result.VideoPath);
 | 
			
		||||
            GlobalInfos.setVideoPath(result.VideoPath);
 | 
			
		||||
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    mediacentername: result.MediacenterName,
 | 
			
		||||
                    onapierror: false
 | 
			
		||||
                });
 | 
			
		||||
                // set tab title to received mediacenter name
 | 
			
		||||
                document.title = result.MediacenterName;
 | 
			
		||||
            },
 | 
			
		||||
            () => {
 | 
			
		||||
                this.setState({onapierror: true});
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
            this.setState({
 | 
			
		||||
                mediacentername: result.MediacenterName
 | 
			
		||||
            });
 | 
			
		||||
            // set tab title to received mediacenter name
 | 
			
		||||
            document.title = result.MediacenterName;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidMount(): void {
 | 
			
		||||
@@ -148,7 +137,6 @@ class App extends React.Component<{}, state> {
 | 
			
		||||
                        </div>
 | 
			
		||||
                        {this.routing()}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {this.state.onapierror ? this.ApiError() : null}
 | 
			
		||||
                </Router>
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -183,11 +171,6 @@ class App extends React.Component<{}, state> {
 | 
			
		||||
            </Switch>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ApiError(): JSX.Element {
 | 
			
		||||
        // on api error show popup and retry and show again if failing..
 | 
			
		||||
        return <NoBackendConnectionPopup onHide={(): void => this.initialAPICall()} />;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default App;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
import {shallow} from 'enzyme';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import {NoBackendConnectionPopup} from './NoBackendConnectionPopup';
 | 
			
		||||
import {getBackendDomain} from '../../../utils/Api';
 | 
			
		||||
 | 
			
		||||
describe('<NoBackendConnectionPopup/>', function () {
 | 
			
		||||
    it('renders without crashing ', function () {
 | 
			
		||||
        const wrapper = shallow(<NoBackendConnectionPopup onHide={() => {}}/>);
 | 
			
		||||
        wrapper.unmount();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('hides on refresh click', function () {
 | 
			
		||||
        const func = jest.fn();
 | 
			
		||||
        const wrapper = shallow(<NoBackendConnectionPopup onHide={func}/>);
 | 
			
		||||
 | 
			
		||||
        expect(func).toBeCalledTimes(0);
 | 
			
		||||
        wrapper.find('button').simulate('click');
 | 
			
		||||
 | 
			
		||||
        expect(func).toBeCalledTimes(1);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('simulate change of textfield', function () {
 | 
			
		||||
        const wrapper = shallow(<NoBackendConnectionPopup onHide={() => {}}/>);
 | 
			
		||||
 | 
			
		||||
        wrapper.find('input').simulate('change', {target: {value: 'testvalue'}});
 | 
			
		||||
 | 
			
		||||
        expect(getBackendDomain()).toBe('testvalue');
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PopupBase from '../PopupBase';
 | 
			
		||||
import style from '../NewActorPopup/NewActorPopup.module.css';
 | 
			
		||||
import {setCustomBackendDomain} from '../../../utils/Api';
 | 
			
		||||
 | 
			
		||||
interface NBCProps {
 | 
			
		||||
    onHide: (_: void) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function NoBackendConnectionPopup(props: NBCProps): JSX.Element {
 | 
			
		||||
    return (
 | 
			
		||||
        <PopupBase title='No connection to backend API!' onHide={props.onHide} height='200px' width='600px'>
 | 
			
		||||
            <div>
 | 
			
		||||
                <input
 | 
			
		||||
                    type='text'
 | 
			
		||||
                    placeholder='http://192.168.0.2'
 | 
			
		||||
                    onChange={(v): void => {
 | 
			
		||||
                        setCustomBackendDomain(v.target.value);
 | 
			
		||||
                    }}
 | 
			
		||||
                />
 | 
			
		||||
            </div>
 | 
			
		||||
            <button className={style.savebtn} onClick={(): void => props.onHide()}>
 | 
			
		||||
                Refresh
 | 
			
		||||
            </button>
 | 
			
		||||
        </PopupBase>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
@@ -13,7 +13,7 @@ import {faPlusCircle} from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import AddActorPopup from '../../elements/Popups/AddActorPopup/AddActorPopup';
 | 
			
		||||
import ActorTile from '../../elements/ActorTile/ActorTile';
 | 
			
		||||
import {withRouter} from 'react-router-dom';
 | 
			
		||||
import {APINode, callAPI, getBackendDomain} from '../../utils/Api';
 | 
			
		||||
import {APINode, callAPI} from '../../utils/Api';
 | 
			
		||||
import {RouteComponentProps} from 'react-router';
 | 
			
		||||
import {GeneralSuccess} from '../../types/GeneralTypes';
 | 
			
		||||
import {ActorType, TagType} from '../../types/VideoTypes';
 | 
			
		||||
@@ -289,9 +289,7 @@ export class Player extends React.Component<myprops, mystate> {
 | 
			
		||||
                                src:
 | 
			
		||||
                                    (process.env.REACT_APP_CUST_BACK_DOMAIN
 | 
			
		||||
                                        ? process.env.REACT_APP_CUST_BACK_DOMAIN
 | 
			
		||||
                                        : getBackendDomain()) +
 | 
			
		||||
                                    GlobalInfos.getVideoPath() +
 | 
			
		||||
                                    result.MovieUrl,
 | 
			
		||||
                                        : GlobalInfos.getVideoPath()) + result.MovieUrl,
 | 
			
		||||
                                type: 'video/mp4',
 | 
			
		||||
                                size: 1080
 | 
			
		||||
                            }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,11 @@ import InfoHeaderItem from '../../elements/InfoHeaderItem/InfoHeaderItem';
 | 
			
		||||
import {faArchive, faBalanceScaleLeft, faRulerVertical} from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import {faAddressCard} from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import {version} from '../../../package.json';
 | 
			
		||||
import {APINode, callAPI, setCustomBackendDomain} from '../../utils/Api';
 | 
			
		||||
import {APINode, callAPI} from '../../utils/Api';
 | 
			
		||||
import {SettingsTypes} from '../../types/ApiTypes';
 | 
			
		||||
import {GeneralSuccess} from '../../types/GeneralTypes';
 | 
			
		||||
 | 
			
		||||
interface state {
 | 
			
		||||
    customapi: boolean;
 | 
			
		||||
    apipath: string;
 | 
			
		||||
    generalSettings: SettingsTypes.loadGeneralSettingsType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -27,8 +25,6 @@ class GeneralSettings extends React.Component<Props, state> {
 | 
			
		||||
        super(props);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            customapi: false,
 | 
			
		||||
            apipath: '',
 | 
			
		||||
            generalSettings: {
 | 
			
		||||
                DarkMode: true,
 | 
			
		||||
                DBSize: 0,
 | 
			
		||||
@@ -121,35 +117,6 @@ class GeneralSettings extends React.Component<Props, state> {
 | 
			
		||||
                                />
 | 
			
		||||
                            </Form.Group>
 | 
			
		||||
                        </Form.Row>
 | 
			
		||||
 | 
			
		||||
                        <Form.Check
 | 
			
		||||
                            type='switch'
 | 
			
		||||
                            id='custom-switch-api'
 | 
			
		||||
                            label='Use custom API url'
 | 
			
		||||
                            checked={this.state.customapi}
 | 
			
		||||
                            onChange={(): void => {
 | 
			
		||||
                                if (this.state.customapi) {
 | 
			
		||||
                                    setCustomBackendDomain('');
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                this.setState({customapi: !this.state.customapi});
 | 
			
		||||
                            }}
 | 
			
		||||
                        />
 | 
			
		||||
                        {this.state.customapi ? (
 | 
			
		||||
                            <Form.Group className={style.customapiform} data-testid='apipath'>
 | 
			
		||||
                                <Form.Label>API Backend url</Form.Label>
 | 
			
		||||
                                <Form.Control
 | 
			
		||||
                                    type='text'
 | 
			
		||||
                                    placeholder='https://127.0.0.1'
 | 
			
		||||
                                    value={this.state.apipath}
 | 
			
		||||
                                    onChange={(e): void => {
 | 
			
		||||
                                        this.setState({apipath: e.target.value});
 | 
			
		||||
                                        setCustomBackendDomain(e.target.value);
 | 
			
		||||
                                    }}
 | 
			
		||||
                                />
 | 
			
		||||
                            </Form.Group>
 | 
			
		||||
                        ) : null}
 | 
			
		||||
 | 
			
		||||
                        <Form.Check
 | 
			
		||||
                            type='switch'
 | 
			
		||||
                            id='custom-switch'
 | 
			
		||||
@@ -209,8 +176,6 @@ class GeneralSettings extends React.Component<Props, state> {
 | 
			
		||||
                            checked={GlobalInfos.isDarkTheme()}
 | 
			
		||||
                            onChange={(): void => {
 | 
			
		||||
                                GlobalInfos.enableDarkTheme(!GlobalInfos.isDarkTheme());
 | 
			
		||||
                                this.forceUpdate();
 | 
			
		||||
                                // todo initiate rerender
 | 
			
		||||
                            }}
 | 
			
		||||
                        />
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,6 @@
 | 
			
		||||
import GlobalInfos from './GlobalInfos';
 | 
			
		||||
 | 
			
		||||
let customBackendURL: string;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * get the domain of the api backend
 | 
			
		||||
 * @return string domain of backend http://x.x.x.x/bla
 | 
			
		||||
 */
 | 
			
		||||
export function getBackendDomain(): string {
 | 
			
		||||
    let userAgent = navigator.userAgent.toLowerCase();
 | 
			
		||||
    if (userAgent.indexOf(' electron/') > -1) {
 | 
			
		||||
        // Electron-specific code - force a custom backendurl
 | 
			
		||||
        return customBackendURL;
 | 
			
		||||
    } else {
 | 
			
		||||
        // use custom only if defined
 | 
			
		||||
        if (customBackendURL) {
 | 
			
		||||
            return customBackendURL;
 | 
			
		||||
        } else {
 | 
			
		||||
            return window.location.origin;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * set a custom backend domain
 | 
			
		||||
 * @param domain a url in format [http://x.x.x.x/somanode]
 | 
			
		||||
 */
 | 
			
		||||
export function setCustomBackendDomain(domain: string): void {
 | 
			
		||||
    customBackendURL = domain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * a helper function to get the api path
 | 
			
		||||
 */
 | 
			
		||||
function getAPIDomain(): string {
 | 
			
		||||
    return getBackendDomain() + '/api/';
 | 
			
		||||
}
 | 
			
		||||
const APIPREFIX: string = '/api/';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * interface how an api request should look like
 | 
			
		||||
@@ -96,7 +62,7 @@ export function refreshAPIToken(callback: (error: string) => void, force?: boole
 | 
			
		||||
        token_type: string; // no camel case allowed because of backendlib
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fetch(getBackendDomain() + '/token', {method: 'POST', body: formData}).then((response) =>
 | 
			
		||||
    fetch('/token', {method: 'POST', body: formData}).then((response) =>
 | 
			
		||||
        response.json().then((result: APIToken) => {
 | 
			
		||||
            if (result.error) {
 | 
			
		||||
                callFuncQue(result.error);
 | 
			
		||||
@@ -223,7 +189,7 @@ export function callAPI<T>(
 | 
			
		||||
): void {
 | 
			
		||||
    checkAPITokenValid(() => {
 | 
			
		||||
        console.log(apiToken);
 | 
			
		||||
        fetch(getAPIDomain() + apinode, {
 | 
			
		||||
        fetch(APIPREFIX + apinode, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            body: JSON.stringify(fd),
 | 
			
		||||
            headers: new Headers({
 | 
			
		||||
@@ -267,7 +233,7 @@ export function callApiUnsafe<T>(
 | 
			
		||||
    callback: (_: T) => void,
 | 
			
		||||
    errorcallback?: (_: string) => void
 | 
			
		||||
): void {
 | 
			
		||||
    fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd)})
 | 
			
		||||
    fetch(APIPREFIX + apinode, {method: 'POST', body: JSON.stringify(fd)})
 | 
			
		||||
        .then((response) => {
 | 
			
		||||
            if (response.status !== 200) {
 | 
			
		||||
                console.log('Error: ' + response.statusText);
 | 
			
		||||
@@ -289,7 +255,7 @@ export function callApiUnsafe<T>(
 | 
			
		||||
 */
 | 
			
		||||
export function callAPIPlain(apinode: APINode, fd: ApiBaseRequest, callback: (_: string) => void): void {
 | 
			
		||||
    checkAPITokenValid(() => {
 | 
			
		||||
        fetch(getAPIDomain() + apinode, {
 | 
			
		||||
        fetch(APIPREFIX + apinode, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            body: JSON.stringify(fd),
 | 
			
		||||
            headers: new Headers({
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,8 @@ class StaticInfos {
 | 
			
		||||
     */
 | 
			
		||||
    enableDarkTheme(enable = true): void {
 | 
			
		||||
        this.darktheme = enable;
 | 
			
		||||
 | 
			
		||||
        // trigger onThemeChange handlers
 | 
			
		||||
        this.handlers.map((func) => {
 | 
			
		||||
            return func();
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user