improve insertion of reindex messages -- prevent empty string lines and add key prop to every new line

This commit is contained in:
Lukas Heiligenbrunner 2021-02-06 22:18:48 +00:00
parent 46aeda73d8
commit 3c32356227
5 changed files with 115 additions and 86 deletions

View File

@ -24,7 +24,9 @@ class ActorOverviewPage extends React.Component<props, state> {
actors: [], actors: [],
NActorPopupVisible: false NActorPopupVisible: false
}; };
}
componentDidMount(): void {
this.fetchAvailableActors(); this.fetchAvailableActors();
} }
@ -36,7 +38,7 @@ class ActorOverviewPage extends React.Component<props, state> {
<Button title='Add Actor' onClick={(): void => this.setState({NActorPopupVisible: true})}/> <Button title='Add Actor' onClick={(): void => this.setState({NActorPopupVisible: true})}/>
</SideBar> </SideBar>
<div className={style.container}> <div className={style.container}>
{this.state.actors.map((el) => (<ActorTile actor={el}/>))} {this.state.actors.map((el) => (<ActorTile key={el.actor_id} actor={el}/>))}
</div> </div>
{this.state.NActorPopupVisible ? {this.state.NActorPopupVisible ?
<NewActorPopup onHide={(): void => { <NewActorPopup onHide={(): void => {

View File

@ -54,9 +54,8 @@ class TagView extends React.Component<props, TagViewState> {
<div className={videocontainerstyle.maincontent}> <div className={videocontainerstyle.maincontent}>
{this.state.loadedtags ? {this.state.loadedtags ?
this.state.loadedtags.map((m) => ( this.state.loadedtags.map((m) => (
<Link to={'/categories/' + m.tag_id}><TagPreview <Link to={'/categories/' + m.tag_id} key={m.tag_id}>
key={m.tag_id} <TagPreview name={m.tag_name}/></Link>
name={m.tag_name}/></Link>
)) : )) :
'loading'} 'loading'}
</div> </div>

View File

@ -104,24 +104,7 @@ export class Player extends React.Component<myprops, mystate> {
<Button onClick={(): void => this.setState({popupvisible: true})} title='Give this Video a Tag' color={{backgroundColor: '#3574fe'}}/> <Button onClick={(): void => this.setState({popupvisible: true})} title='Give this Video a Tag' color={{backgroundColor: '#3574fe'}}/>
<Button title='Delete Video' onClick={(): void => {this.deleteVideo();}} color={{backgroundColor: 'red'}}/> <Button title='Delete Video' onClick={(): void => {this.deleteVideo();}} color={{backgroundColor: 'red'}}/>
</div> </div>
{/* rendering of actor tiles */} {this.assembleActorTiles()}
<div className={style.actorcontainer}>
{this.state.actors ?
this.state.actors.map((actr: ActorType) => (
<ActorTile actor={actr}/>
)) : <></>
}
<div className={style.actorAddTile} onClick={(): void => {
this.addActor();
}}>
<div className={style.actorAddTile_thumbnail}>
<FontAwesomeIcon style={{
lineHeight: '130px'
}} icon={faPlusCircle} size='5x'/>
</div>
<div className={style.actorAddTile_name}>Add Actor</div>
</div>
</div>
</div> </div>
<button className={style.closebutton} onClick={(): void => this.closebtn()}>Close</button> <button className={style.closebutton} onClick={(): void => this.closebtn()}>Close</button>
{ {
@ -148,7 +131,7 @@ export class Player extends React.Component<myprops, mystate> {
<Line/> <Line/>
<SideBarTitle>Tags:</SideBarTitle> <SideBarTitle>Tags:</SideBarTitle>
{this.state.tags.map((m: TagType) => ( {this.state.tags.map((m: TagType) => (
<Tag tagInfo={m}/> <Tag key={m.tag_id} tagInfo={m}/>
))} ))}
<Line/> <Line/>
<SideBarTitle>Tag Quickadd:</SideBarTitle> <SideBarTitle>Tag Quickadd:</SideBarTitle>
@ -164,6 +147,58 @@ export class Player extends React.Component<myprops, mystate> {
); );
} }
/**
* rendering of actor tiles
*/
private assembleActorTiles(): JSX.Element {
return (
<div className={style.actorcontainer}>
{this.state.actors ?
this.state.actors.map((actr: ActorType) => (
<ActorTile key={actr.actor_id} actor={actr}/>
)) : <></>
}
<div className={style.actorAddTile} onClick={(): void => {
this.addActor();
}}>
<div className={style.actorAddTile_thumbnail}>
<FontAwesomeIcon style={{
lineHeight: '130px'
}} icon={faPlusCircle} size='5x'/>
</div>
<div className={style.actorAddTile_name}>Add Actor</div>
</div>
</div>
);
}
/**
* handle the popovers generated according to state changes
* @returns {JSX.Element}
*/
handlePopOvers(): JSX.Element {
return (
<>
{this.state.popupvisible ?
<AddTagPopup onHide={(): void => {
this.setState({popupvisible: false});
}}
submit={this.quickAddTag}
movie_id={this.state.movie_id}/> :
null
}
{
this.state.actorpopupvisible ?
<AddActorPopup onHide={(): void => {
this.refetchActors();
this.setState({actorpopupvisible: false});
}} movie_id={this.state.movie_id}/> : null
}
</>
);
}
/** /**
* quick add callback to add tag to db and change gui correctly * quick add callback to add tag to db and change gui correctly
* @param tagId id of tag to add * @param tagId id of tag to add
@ -210,32 +245,6 @@ export class Player extends React.Component<myprops, mystate> {
}); });
} }
/**
* handle the popovers generated according to state changes
* @returns {JSX.Element}
*/
handlePopOvers(): JSX.Element {
return (
<>
{this.state.popupvisible ?
<AddTagPopup onHide={(): void => {
this.setState({popupvisible: false});
}}
submit={this.quickAddTag}
movie_id={this.state.movie_id}/> :
null
}
{
this.state.actorpopupvisible ?
<AddActorPopup onHide={(): void => {
this.refetchActors();
this.setState({actorpopupvisible: false});
}} movie_id={this.state.movie_id}/> : null
}
</>
);
}
/** /**
* fetch all the required infos of a video from backend * fetch all the required infos of a video from backend
*/ */

View File

@ -1,6 +1,7 @@
import {shallow} from 'enzyme'; import {shallow} from 'enzyme';
import React from 'react'; import React from 'react';
import MovieSettings from './MovieSettings'; import MovieSettings from './MovieSettings';
import {callAPI} from "../../utils/Api";
describe('<MovieSettings/>', function () { describe('<MovieSettings/>', function () {
it('renders without crashing ', function () { it('renders without crashing ', function () {
@ -49,64 +50,79 @@ describe('<MovieSettings/>', function () {
}); });
}); });
it('content available received and in state', done => { it('content available received and in state', () => {
global.fetch = global.prepareFetchApi({ const wrapper = shallow(<MovieSettings/>);
callAPIMock({
contentAvailable: true, contentAvailable: true,
message: 'firstline\nsecondline' message: 'firstline\nsecondline'
}); })
const wrapper = shallow(<MovieSettings/>);
wrapper.instance().updateStatus(); wrapper.instance().updateStatus();
process.nextTick(() => { expect(wrapper.state()).toMatchObject({
expect(wrapper.state()).toMatchObject({ text: [
text: [ 'firstline',
'firstline', 'secondline'
'secondline' ]
]
});
global.fetch.mockClear();
done();
}); });
}); });
it('test reindex with no content available', done => { it('test reindex with no content available', () => {
global.fetch = global.prepareFetchApi({ callAPIMock({
contentAvailable: false contentAvailable: false
}); })
global.clearInterval = jest.fn(); global.clearInterval = jest.fn();
const wrapper = shallow(<MovieSettings/>); const wrapper = shallow(<MovieSettings/>);
wrapper.instance().updateStatus(); wrapper.instance().updateStatus();
process.nextTick(() => { // expect the refresh interval to be cleared
// expect the refresh interval to be cleared expect(global.clearInterval).toBeCalledTimes(1);
expect(global.clearInterval).toBeCalledTimes(1);
// expect startbtn to be reenabled // expect startbtn to be reenabled
expect(wrapper.state()).toMatchObject({startbtnDisabled: false}); expect(wrapper.state()).toMatchObject({startbtnDisabled: false});
global.fetch.mockClear();
done();
});
}); });
it('test simulate gravity cleanup', done => { it('test simulate gravity cleanup', () => {
global.fetch = global.prepareFetchApi('mmi'); // global.fetch = global.prepareFetchApi('mmi');
callAPIMock({})
const wrapper = shallow(<MovieSettings/>); const wrapper = shallow(<MovieSettings/>);
wrapper.instance().setState = jest.fn(), wrapper.instance().setState = jest.fn();
wrapper.find('button').findWhere(e => e.text() === 'Cleanup Gravity' && e.type() === 'button').simulate('click'); wrapper.find('button').findWhere(e => e.text() === 'Cleanup Gravity' && e.type() === 'button').simulate('click');
// initial send of reindex request to server // initial send of reindex request to server
expect(global.fetch).toBeCalledTimes(1); expect(callAPI).toBeCalledTimes(1);
process.nextTick(() => { expect(wrapper.instance().setState).toBeCalledTimes(1);
expect(wrapper.instance().setState).toBeCalledTimes(1); });
global.fetch.mockClear(); it('test no textDiv insertion if string is empty', function () {
done(); const wrapper = shallow(<MovieSettings/>);
callAPIMock({
contentAvailable: true,
message: 'test'
})
wrapper.instance().updateStatus();
expect(wrapper.state()).toMatchObject({
text: ['test']
});
// expect an untouched state if we try to add an empty string...
callAPIMock({
contentAvailable: true,
message: ''
})
wrapper.instance().updateStatus();
expect(wrapper.state()).toMatchObject({
text: ['test']
}); });
}); });
}); });

View File

@ -47,7 +47,7 @@ class MovieSettings extends React.Component<props, state> {
onClick={(): void => {this.cleanupGravity();}}>Cleanup Gravity onClick={(): void => {this.cleanupGravity();}}>Cleanup Gravity
</button> </button>
<div className={style.indextextarea}>{this.state.text.map(m => ( <div className={style.indextextarea}>{this.state.text.map(m => (
<div className='textarea-element'>{m}</div> <div key={m} className='textarea-element'>{m}</div>
))}</div> ))}</div>
</> </>
); );
@ -85,8 +85,11 @@ class MovieSettings extends React.Component<props, state> {
*/ */
updateStatus = (): void => { updateStatus = (): void => {
callAPI(APINode.Settings, {action: 'getStatusMessage'}, (result: SettingsTypes.getStatusMessageType) => { callAPI(APINode.Settings, {action: 'getStatusMessage'}, (result: SettingsTypes.getStatusMessageType) => {
if (result.contentAvailable === true) { if (result.contentAvailable) {
// ignore if message is empty
console.log(result); console.log(result);
if(result.message === '') return;
// todo 2020-07-4: scroll to bottom of div here // todo 2020-07-4: scroll to bottom of div here
this.setState({ this.setState({
// insert a string for each line // insert a string for each line