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:
parent
c0405cd79a
commit
d9d6907745
@ -1,13 +1,14 @@
|
|||||||
image: node:14
|
image: node:14
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build_frontend
|
||||||
|
- build_backend
|
||||||
- test
|
- test
|
||||||
- packaging
|
- packaging
|
||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
Minimize_Frontend:
|
Minimize_Frontend:
|
||||||
stage: build
|
stage: build_frontend
|
||||||
before_script:
|
before_script:
|
||||||
- yarn install --cache-folder .yarn
|
- yarn install --cache-folder .yarn
|
||||||
script:
|
script:
|
||||||
@ -25,11 +26,15 @@ Minimize_Frontend:
|
|||||||
|
|
||||||
Build_Backend:
|
Build_Backend:
|
||||||
image: golang:latest
|
image: golang:latest
|
||||||
stage: build
|
stage: build_backend
|
||||||
script:
|
script:
|
||||||
- cd apiGo
|
- cd apiGo
|
||||||
- go build -v -o openmediacenter
|
- go build -v -o openmediacenter
|
||||||
- env GOOS=windows GOARCH=amd64 go build -v -o openmediacenter.exe
|
- cp -r ../build/ ./static/
|
||||||
|
- go build -v -tags static -o openmediacenter_full
|
||||||
|
- env GOOS=windows GOARCH=amd64 go build -v -tags static -o openmediacenter.exe
|
||||||
|
needs:
|
||||||
|
- Minimize_Frontend
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 days
|
expire_in: 2 days
|
||||||
paths:
|
paths:
|
||||||
@ -41,6 +46,7 @@ Frontend_Tests:
|
|||||||
- yarn install --cache-folder .yarn
|
- yarn install --cache-folder .yarn
|
||||||
script:
|
script:
|
||||||
- yarn run test
|
- yarn run test
|
||||||
|
needs: []
|
||||||
artifacts:
|
artifacts:
|
||||||
reports:
|
reports:
|
||||||
junit:
|
junit:
|
||||||
@ -58,6 +64,7 @@ Backend_Tests:
|
|||||||
- cd apiGo
|
- cd apiGo
|
||||||
- go get -u github.com/jstemmer/go-junit-report
|
- go get -u github.com/jstemmer/go-junit-report
|
||||||
- go test -v ./... 2>&1 | go-junit-report -set-exit-code > report.xml
|
- go test -v ./... 2>&1 | go-junit-report -set-exit-code > report.xml
|
||||||
|
needs: []
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"openmediacenter/apiGo/api/oauth"
|
"openmediacenter/apiGo/api/oauth"
|
||||||
)
|
)
|
||||||
@ -37,7 +36,7 @@ func AddHandler(action string, apiNode int, n interface{}, h func() []byte) {
|
|||||||
handlers = append(handlers, Handler{action, h, n, apiNode})
|
handlers = append(handlers, Handler{action, h, n, apiNode})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServerInit(port uint16) {
|
func ServerInit() {
|
||||||
http.Handle(APIPREFIX+"/video", oauth.ValidateToken(videoHandler))
|
http.Handle(APIPREFIX+"/video", oauth.ValidateToken(videoHandler))
|
||||||
http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(tagHandler))
|
http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(tagHandler))
|
||||||
http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler))
|
http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler))
|
||||||
@ -48,9 +47,6 @@ func ServerInit(port uint16) {
|
|||||||
|
|
||||||
// initialize oauth service and add corresponding auth routes
|
// initialize oauth service and add corresponding auth routes
|
||||||
oauth.InitOAuth()
|
oauth.InitOAuth()
|
||||||
|
|
||||||
fmt.Printf("OpenMediacenter server up and running on port %d\n", port)
|
|
||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAPICall(action string, requestBody string, apiNode int) []byte {
|
func handleAPICall(action string, requestBody string, apiNode int) []byte {
|
||||||
|
@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"openmediacenter/apiGo/database/settings"
|
"openmediacenter/apiGo/database/settings"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddInitHandlers() {
|
func AddInitHandlers() {
|
||||||
@ -20,11 +22,15 @@ func passwordNeeded() {
|
|||||||
VideoPath string
|
VideoPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regexMatchUrl := regexp.MustCompile("^http(|s):\\/\\/([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}:[0-9]{1,5}")
|
||||||
|
videoUrl := regexMatchUrl.FindString(sett.VideoPath)
|
||||||
|
serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl)
|
||||||
|
|
||||||
res := InitialDataTypeResponse{
|
res := InitialDataTypeResponse{
|
||||||
DarkMode: sett.DarkMode,
|
DarkMode: sett.DarkMode,
|
||||||
Pasword: sett.Pasword != "-1",
|
Pasword: sett.Pasword != "-1",
|
||||||
MediacenterName: sett.Mediacenter_name,
|
MediacenterName: sett.Mediacenter_name,
|
||||||
VideoPath: sett.VideoPath,
|
VideoPath: serverVideoPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
str, _ := json.Marshal(res)
|
str, _ := json.Marshal(res)
|
||||||
|
@ -3,12 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
"openmediacenter/apiGo/api"
|
"openmediacenter/apiGo/api"
|
||||||
"openmediacenter/apiGo/database"
|
"openmediacenter/apiGo/database"
|
||||||
|
"openmediacenter/apiGo/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("init OpenMediaCenter server")
|
fmt.Println("init OpenMediaCenter server")
|
||||||
|
port := 8081
|
||||||
|
|
||||||
db, verbose, pathPrefix := handleCommandLineArguments()
|
db, verbose, pathPrefix := handleCommandLineArguments()
|
||||||
// todo some verbosity logger or sth
|
// todo some verbosity logger or sth
|
||||||
@ -28,7 +32,13 @@ func main() {
|
|||||||
api.AddActorsHandlers()
|
api.AddActorsHandlers()
|
||||||
api.AddInitHandlers()
|
api.AddInitHandlers()
|
||||||
|
|
||||||
api.ServerInit(8081)
|
// add the static files
|
||||||
|
static.ServeStaticFiles()
|
||||||
|
|
||||||
|
api.ServerInit()
|
||||||
|
|
||||||
|
fmt.Printf("OpenMediacenter server up and running on port %d\n", port)
|
||||||
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCommandLineArguments() (*database.DatabaseConfig, bool, *string) {
|
func handleCommandLineArguments() (*database.DatabaseConfig, bool, *string) {
|
||||||
|
89
apiGo/static/StaticServe.go
Normal file
89
apiGo/static/StaticServe.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// +build static
|
||||||
|
|
||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"openmediacenter/apiGo/database/settings"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed build
|
||||||
|
var staticFiles embed.FS
|
||||||
|
|
||||||
|
func ServeStaticFiles() {
|
||||||
|
// http.FS can be used to create a http Filesystem
|
||||||
|
subfs, _ := fs.Sub(staticFiles, "build")
|
||||||
|
staticFS := http.FS(subfs)
|
||||||
|
fs := http.FileServer(staticFS)
|
||||||
|
|
||||||
|
// Serve static files
|
||||||
|
http.Handle("/", validatePrefix(fs))
|
||||||
|
|
||||||
|
// we need to proxy the videopath to somewhere in a standalone binary
|
||||||
|
proxyVideoURL()
|
||||||
|
}
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
proxy *httputil.ReverseProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.proxy.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func proxyVideoURL() {
|
||||||
|
conf := settings.LoadSettings()
|
||||||
|
|
||||||
|
// match base url
|
||||||
|
regexMatchUrl := regexp.MustCompile("^http(|s):\\/\\/([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}:[0-9]{1,5}")
|
||||||
|
|
||||||
|
var videoUrl *url.URL
|
||||||
|
if regexMatchUrl.MatchString(conf.VideoPath) {
|
||||||
|
fmt.Println("matches string...")
|
||||||
|
var err error
|
||||||
|
videoUrl, err = url.Parse(regexMatchUrl.FindString(conf.VideoPath))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
videoUrl, _ = url.Parse("http://127.0.0.1:8081")
|
||||||
|
}
|
||||||
|
|
||||||
|
director := func(req *http.Request) {
|
||||||
|
req.URL.Scheme = videoUrl.Scheme
|
||||||
|
req.URL.Host = videoUrl.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
serverVideoPath := strings.TrimPrefix(conf.VideoPath, regexMatchUrl.FindString(conf.VideoPath))
|
||||||
|
|
||||||
|
reverseProxy := &httputil.ReverseProxy{Director: director}
|
||||||
|
handler := handler{proxy: reverseProxy}
|
||||||
|
http.Handle(serverVideoPath, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatePrefix check if requested path is a file -- if not proceed with index.html
|
||||||
|
func validatePrefix(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
regex := regexp.MustCompile("\\..*$")
|
||||||
|
matchFile := regex.MatchString(r.URL.Path)
|
||||||
|
|
||||||
|
if matchFile {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
|
r2 := new(http.Request)
|
||||||
|
*r2 = *r
|
||||||
|
r2.URL = new(url.URL)
|
||||||
|
*r2.URL = *r.URL
|
||||||
|
r2.URL.Path = "/"
|
||||||
|
r2.URL.RawPath = "/"
|
||||||
|
h.ServeHTTP(w, r2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
6
apiGo/static/StaticServe_apionly.go
Normal file
6
apiGo/static/StaticServe_apionly.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// +build !static
|
||||||
|
|
||||||
|
package static
|
||||||
|
|
||||||
|
// add nothing on no static build
|
||||||
|
func ServeStaticFiles() {}
|
23
src/App.tsx
23
src/App.tsx
@ -10,7 +10,6 @@ import style from './App.module.css';
|
|||||||
import SettingsPage from './pages/SettingsPage/SettingsPage';
|
import SettingsPage from './pages/SettingsPage/SettingsPage';
|
||||||
import CategoryPage from './pages/CategoryPage/CategoryPage';
|
import CategoryPage from './pages/CategoryPage/CategoryPage';
|
||||||
import {APINode, apiTokenValid, callApiUnsafe, refreshAPIToken} from './utils/Api';
|
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 {BrowserRouter as Router, NavLink, Route, Switch} from 'react-router-dom';
|
||||||
import Player from './pages/Player/Player';
|
import Player from './pages/Player/Player';
|
||||||
@ -22,7 +21,6 @@ import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage';
|
|||||||
interface state {
|
interface state {
|
||||||
password: boolean | null; // null if uninitialized - true if pwd needed false if not needed
|
password: boolean | null; // null if uninitialized - true if pwd needed false if not needed
|
||||||
mediacentername: string;
|
mediacentername: string;
|
||||||
onapierror: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,7 +48,6 @@ class App extends React.Component<{}, state> {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
mediacentername: 'OpenMediaCenter',
|
mediacentername: 'OpenMediaCenter',
|
||||||
onapierror: false,
|
|
||||||
password: pwdneeded
|
password: pwdneeded
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,26 +74,18 @@ class App extends React.Component<{}, state> {
|
|||||||
|
|
||||||
initialAPICall(): void {
|
initialAPICall(): void {
|
||||||
// this is the first api call so if it fails we know there is no connection to backend
|
// this is the first api call so if it fails we know there is no connection to backend
|
||||||
callApiUnsafe(
|
callApiUnsafe(APINode.Init, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => {
|
||||||
APINode.Init,
|
|
||||||
{action: 'loadInitialData'},
|
|
||||||
(result: SettingsTypes.initialApiCallData) => {
|
|
||||||
// set theme
|
// set theme
|
||||||
GlobalInfos.enableDarkTheme(result.DarkMode);
|
GlobalInfos.enableDarkTheme(result.DarkMode);
|
||||||
|
|
||||||
GlobalInfos.setVideoPath(result.VideoPath);
|
GlobalInfos.setVideoPath(result.VideoPath);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
mediacentername: result.MediacenterName,
|
mediacentername: result.MediacenterName
|
||||||
onapierror: false
|
|
||||||
});
|
});
|
||||||
// set tab title to received mediacenter name
|
// set tab title to received mediacenter name
|
||||||
document.title = result.MediacenterName;
|
document.title = result.MediacenterName;
|
||||||
},
|
});
|
||||||
() => {
|
|
||||||
this.setState({onapierror: true});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
@ -148,7 +137,6 @@ class App extends React.Component<{}, state> {
|
|||||||
</div>
|
</div>
|
||||||
{this.routing()}
|
{this.routing()}
|
||||||
</div>
|
</div>
|
||||||
{this.state.onapierror ? this.ApiError() : null}
|
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -183,11 +171,6 @@ class App extends React.Component<{}, state> {
|
|||||||
</Switch>
|
</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;
|
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 AddActorPopup from '../../elements/Popups/AddActorPopup/AddActorPopup';
|
||||||
import ActorTile from '../../elements/ActorTile/ActorTile';
|
import ActorTile from '../../elements/ActorTile/ActorTile';
|
||||||
import {withRouter} from 'react-router-dom';
|
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 {RouteComponentProps} from 'react-router';
|
||||||
import {GeneralSuccess} from '../../types/GeneralTypes';
|
import {GeneralSuccess} from '../../types/GeneralTypes';
|
||||||
import {ActorType, TagType} from '../../types/VideoTypes';
|
import {ActorType, TagType} from '../../types/VideoTypes';
|
||||||
@ -289,9 +289,7 @@ export class Player extends React.Component<myprops, mystate> {
|
|||||||
src:
|
src:
|
||||||
(process.env.REACT_APP_CUST_BACK_DOMAIN
|
(process.env.REACT_APP_CUST_BACK_DOMAIN
|
||||||
? 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',
|
type: 'video/mp4',
|
||||||
size: 1080
|
size: 1080
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,11 @@ import InfoHeaderItem from '../../elements/InfoHeaderItem/InfoHeaderItem';
|
|||||||
import {faArchive, faBalanceScaleLeft, faRulerVertical} from '@fortawesome/free-solid-svg-icons';
|
import {faArchive, faBalanceScaleLeft, faRulerVertical} from '@fortawesome/free-solid-svg-icons';
|
||||||
import {faAddressCard} from '@fortawesome/free-regular-svg-icons';
|
import {faAddressCard} from '@fortawesome/free-regular-svg-icons';
|
||||||
import {version} from '../../../package.json';
|
import {version} from '../../../package.json';
|
||||||
import {APINode, callAPI, setCustomBackendDomain} from '../../utils/Api';
|
import {APINode, callAPI} from '../../utils/Api';
|
||||||
import {SettingsTypes} from '../../types/ApiTypes';
|
import {SettingsTypes} from '../../types/ApiTypes';
|
||||||
import {GeneralSuccess} from '../../types/GeneralTypes';
|
import {GeneralSuccess} from '../../types/GeneralTypes';
|
||||||
|
|
||||||
interface state {
|
interface state {
|
||||||
customapi: boolean;
|
|
||||||
apipath: string;
|
|
||||||
generalSettings: SettingsTypes.loadGeneralSettingsType;
|
generalSettings: SettingsTypes.loadGeneralSettingsType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +25,6 @@ class GeneralSettings extends React.Component<Props, state> {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
customapi: false,
|
|
||||||
apipath: '',
|
|
||||||
generalSettings: {
|
generalSettings: {
|
||||||
DarkMode: true,
|
DarkMode: true,
|
||||||
DBSize: 0,
|
DBSize: 0,
|
||||||
@ -121,35 +117,6 @@ class GeneralSettings extends React.Component<Props, state> {
|
|||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
</Form.Row>
|
</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
|
<Form.Check
|
||||||
type='switch'
|
type='switch'
|
||||||
id='custom-switch'
|
id='custom-switch'
|
||||||
@ -209,8 +176,6 @@ class GeneralSettings extends React.Component<Props, state> {
|
|||||||
checked={GlobalInfos.isDarkTheme()}
|
checked={GlobalInfos.isDarkTheme()}
|
||||||
onChange={(): void => {
|
onChange={(): void => {
|
||||||
GlobalInfos.enableDarkTheme(!GlobalInfos.isDarkTheme());
|
GlobalInfos.enableDarkTheme(!GlobalInfos.isDarkTheme());
|
||||||
this.forceUpdate();
|
|
||||||
// todo initiate rerender
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -1,40 +1,6 @@
|
|||||||
import GlobalInfos from './GlobalInfos';
|
import GlobalInfos from './GlobalInfos';
|
||||||
|
|
||||||
let customBackendURL: string;
|
const APIPREFIX: string = '/api/';
|
||||||
|
|
||||||
/**
|
|
||||||
* 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/';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* interface how an api request should look like
|
* 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
|
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) => {
|
response.json().then((result: APIToken) => {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
callFuncQue(result.error);
|
callFuncQue(result.error);
|
||||||
@ -223,7 +189,7 @@ export function callAPI<T>(
|
|||||||
): void {
|
): void {
|
||||||
checkAPITokenValid(() => {
|
checkAPITokenValid(() => {
|
||||||
console.log(apiToken);
|
console.log(apiToken);
|
||||||
fetch(getAPIDomain() + apinode, {
|
fetch(APIPREFIX + apinode, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(fd),
|
body: JSON.stringify(fd),
|
||||||
headers: new Headers({
|
headers: new Headers({
|
||||||
@ -267,7 +233,7 @@ export function callApiUnsafe<T>(
|
|||||||
callback: (_: T) => void,
|
callback: (_: T) => void,
|
||||||
errorcallback?: (_: string) => void
|
errorcallback?: (_: string) => void
|
||||||
): void {
|
): void {
|
||||||
fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd)})
|
fetch(APIPREFIX + apinode, {method: 'POST', body: JSON.stringify(fd)})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log('Error: ' + response.statusText);
|
console.log('Error: ' + response.statusText);
|
||||||
@ -289,7 +255,7 @@ export function callApiUnsafe<T>(
|
|||||||
*/
|
*/
|
||||||
export function callAPIPlain(apinode: APINode, fd: ApiBaseRequest, callback: (_: string) => void): void {
|
export function callAPIPlain(apinode: APINode, fd: ApiBaseRequest, callback: (_: string) => void): void {
|
||||||
checkAPITokenValid(() => {
|
checkAPITokenValid(() => {
|
||||||
fetch(getAPIDomain() + apinode, {
|
fetch(APIPREFIX + apinode, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(fd),
|
body: JSON.stringify(fd),
|
||||||
headers: new Headers({
|
headers: new Headers({
|
||||||
|
@ -23,6 +23,8 @@ class StaticInfos {
|
|||||||
*/
|
*/
|
||||||
enableDarkTheme(enable = true): void {
|
enableDarkTheme(enable = true): void {
|
||||||
this.darktheme = enable;
|
this.darktheme = enable;
|
||||||
|
|
||||||
|
// trigger onThemeChange handlers
|
||||||
this.handlers.map((func) => {
|
this.handlers.map((func) => {
|
||||||
return func();
|
return func();
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user