Server select overlay working.

This commit is contained in:
Daniel Scalzi 2020-08-31 20:31:50 -04:00
parent dc00e6104b
commit 574b362d12
No known key found for this signature in database
GPG Key ID: D18EA3FB4B142A57
8 changed files with 185 additions and 49 deletions

53
package-lock.json generated
View File

@ -1361,6 +1361,38 @@
} }
} }
}, },
"@eslint/eslintrc": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.0.tgz",
"integrity": "sha512-bfL5365QSCmH6cPeFT7Ywclj8C7LiF7sO6mUGzZhtAMV7iID1Euq6740u/SRi4C80NOnVz/CEfK8/HO+nCAPJg==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
"debug": "^4.1.1",
"import-fresh": "^3.2.1",
"strip-json-comments": "^3.1.1"
},
"dependencies": {
"ajv": {
"version": "6.12.4",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
"integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
}
}
},
"@sindresorhus/is": { "@sindresorhus/is": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.2.tgz",
@ -1527,9 +1559,9 @@
} }
}, },
"@types/lodash": { "@types/lodash": {
"version": "4.14.160", "version": "4.14.161",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.160.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz",
"integrity": "sha512-aP03BShJoO+WVndoVj/WNcB/YBPt+CIU1mvaao2GRAHy2yg4pT/XS4XnVHEQBjPJGycWf/9seKEO9vopTJGkvA==", "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==",
"dev": true "dev": true
}, },
"@types/minimatch": { "@types/minimatch": {
@ -1556,9 +1588,9 @@
"dev": true "dev": true
}, },
"@types/react": { "@types/react": {
"version": "16.9.48", "version": "16.9.49",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.48.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.49.tgz",
"integrity": "sha512-4ykBVswgYitPGMXFRxJCHkxJDU2rjfU3/zw67f8+dB7sNdVJXsrwqoYxz/stkAucymnEEbRPFmX7Ce5Mc/kJCw==", "integrity": "sha512-DtLFjSj0OYAdVLBbyjhuV9CdGVHCkHn2R+xr3XkBvK2rS1Y1tkc14XSGjYgm5Fjjr90AxH9tiSzc1pCFMGO06g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/prop-types": "*", "@types/prop-types": "*",
@ -4690,12 +4722,13 @@
"dev": true "dev": true
}, },
"eslint": { "eslint": {
"version": "7.7.0", "version": "7.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.7.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.0.tgz",
"integrity": "sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==", "integrity": "sha512-qgtVyLZqKd2ZXWnLQA4NtVbOyH56zivOAdBFWE54RFkSZjokzNrcP4Z0eVWsZ+84ByXv+jL9k/wE1ENYe8xRFw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.0.0", "@babel/code-frame": "^7.0.0",
"@eslint/eslintrc": "^0.1.0",
"ajv": "^6.10.0", "ajv": "^6.10.0",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.2",
@ -4705,7 +4738,7 @@
"eslint-scope": "^5.1.0", "eslint-scope": "^5.1.0",
"eslint-utils": "^2.1.0", "eslint-utils": "^2.1.0",
"eslint-visitor-keys": "^1.3.0", "eslint-visitor-keys": "^1.3.0",
"espree": "^7.2.0", "espree": "^7.3.0",
"esquery": "^1.2.0", "esquery": "^1.2.0",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"file-entry-cache": "^5.0.1", "file-entry-cache": "^5.0.1",

View File

@ -56,10 +56,10 @@
"@types/electron-devtools-installer": "^2.2.0", "@types/electron-devtools-installer": "^2.2.0",
"@types/fs-extra": "^9.0.1", "@types/fs-extra": "^9.0.1",
"@types/jquery": "^3.5.1", "@types/jquery": "^3.5.1",
"@types/lodash": "^4.14.160", "@types/lodash": "^4.14.161",
"@types/mocha": "^8.0.3", "@types/mocha": "^8.0.3",
"@types/node": "^12.12.54", "@types/node": "^12.12.54",
"@types/react": "^16.9.48", "@types/react": "^16.9.49",
"@types/react-dom": "^16.9.8", "@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9", "@types/react-redux": "^7.1.9",
"@types/react-transition-group": "^4.4.0", "@types/react-transition-group": "^4.4.0",
@ -77,7 +77,7 @@
"electron-devtools-installer": "^3.1.1", "electron-devtools-installer": "^3.1.1",
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
"electron-webpack-ts": "^4.0.1", "electron-webpack-ts": "^4.0.1",
"eslint": "^7.7.0", "eslint": "^7.8.0",
"eslint-plugin-react": "^7.20.6", "eslint-plugin-react": "^7.20.6",
"helios-distribution-types": "1.0.0-pre.1", "helios-distribution-types": "1.0.0-pre.1",
"mocha": "^8.1.3", "mocha": "^8.1.3",

View File

@ -1,28 +1,43 @@
import { Distribution, Server, Module, Type, Required as HeliosRequired } from 'helios-distribution-types' import { Distribution, Server, Module, Type, Required as HeliosRequired } from 'helios-distribution-types'
import { MavenComponents, MavenUtil } from 'common/util/MavenUtil' import { MavenComponents, MavenUtil } from 'common/util/MavenUtil'
import { join } from 'path' import { join } from 'path'
import { LoggerUtil } from 'common/logging/loggerutil'
const logger = LoggerUtil.getLogger('DistributionFactory')
export class HeliosDistribution { export class HeliosDistribution {
private mainServerIndex: number private mainServerIndex!: number
public readonly servers: HeliosServer[] public readonly servers: HeliosServer[]
constructor( constructor(
public readonly rawDistribution: Distribution public readonly rawDistribution: Distribution
) { ) {
this.resolveMainServerIndex()
this.servers = this.rawDistribution.servers.map(s => new HeliosServer(s)) this.servers = this.rawDistribution.servers.map(s => new HeliosServer(s))
this.mainServerIndex = this.indexOfMainServer()
} }
private indexOfMainServer(): number { private resolveMainServerIndex(): void {
for(let i=0; i<this.servers.length; i++) {
if(this.servers[i].rawServer.mainServer) { if(this.rawDistribution.servers.length > 0) {
return i for(let i=0; i<this.rawDistribution.servers.length; i++) {
if(this.mainServerIndex == null) {
if(this.rawDistribution.servers[i].mainServer) {
this.mainServerIndex = i
}
} else {
this.rawDistribution.servers[i].mainServer = false
}
} }
if(this.mainServerIndex == null) {
this.mainServerIndex = 0
this.rawDistribution.servers[this.mainServerIndex].mainServer = true
}
} else {
logger.warn('Distribution has 0 configured servers. This doesnt seem right..')
this.mainServerIndex = 0
} }
return 0
} }
public getMainServer(): HeliosServer | null { public getMainServer(): HeliosServer | null {

View File

@ -19,6 +19,7 @@ import { join } from 'path'
import { AppActionDispatch } from '../redux/actions/appActions' import { AppActionDispatch } from '../redux/actions/appActions'
import { OverlayPushAction, OverlayActionDispatch } from '../redux/actions/overlayActions' import { OverlayPushAction, OverlayActionDispatch } from '../redux/actions/overlayActions'
import { LoggerUtil } from 'common/logging/loggerutil'
import { DistributionAPI } from 'common/distribution/DistributionAPI' import { DistributionAPI } from 'common/distribution/DistributionAPI'
import { getServerStatus } from 'common/mojang/net/ServerStatusAPI' import { getServerStatus } from 'common/mojang/net/ServerStatusAPI'
import { Distribution } from 'helios-distribution-types' import { Distribution } from 'helios-distribution-types'
@ -37,6 +38,7 @@ function setBackground(id: number) {
interface ApplicationProps { interface ApplicationProps {
currentView: View currentView: View
overlayQueue: OverlayPushAction<unknown>[] overlayQueue: OverlayPushAction<unknown>[]
distribution: HeliosDistribution
} }
interface ApplicationState { interface ApplicationState {
@ -49,7 +51,8 @@ interface ApplicationState {
const mapState = (state: StoreType): Partial<ApplicationProps> => { const mapState = (state: StoreType): Partial<ApplicationProps> => {
return { return {
currentView: state.currentView, currentView: state.currentView,
overlayQueue: state.overlayQueue overlayQueue: state.overlayQueue,
distribution: state.app.distribution!
} }
} }
const mapDispatch = { const mapDispatch = {
@ -60,6 +63,8 @@ const mapDispatch = {
class Application extends React.Component<ApplicationProps & typeof mapDispatch, ApplicationState> { class Application extends React.Component<ApplicationProps & typeof mapDispatch, ApplicationState> {
private readonly logger = LoggerUtil.getLogger('Application')
private bkid!: number private bkid!: number
constructor(props: ApplicationProps & typeof mapDispatch) { constructor(props: ApplicationProps & typeof mapDispatch) {
@ -185,26 +190,31 @@ class Application extends React.Component<ApplicationProps & typeof mapDispatch,
console.log(serverStatus) console.log(serverStatus)
} }
}) })
this.props.pushGenericOverlay({ this.props.pushServerSelectOverlay({
title: 'Test Title 2', servers: this.props.distribution.servers,
description: 'Test Description', selectedId: this.props.distribution.servers[0].rawServer.id,
dismissible: true onSelection: (serverId: string) => this.logger.info('Server Selection Change:', serverId)
}) })
this.props.pushGenericOverlay({ // this.props.pushGenericOverlay({
title: 'Test Title 3', // title: 'Test Title 2',
description: 'Test Description', // description: 'Test Description',
dismissible: true // dismissible: true
}) // })
this.props.pushGenericOverlay({ // this.props.pushGenericOverlay({
title: 'Test Title 4', // title: 'Test Title 3',
description: 'Test Description', // description: 'Test Description',
dismissible: true // dismissible: true
}) // })
this.props.pushGenericOverlay({ // this.props.pushGenericOverlay({
title: 'Test Title IMPORTANT', // title: 'Test Title 4',
description: 'Test Description', // description: 'Test Description',
dismissible: true // dismissible: true
}, true) // })
// this.props.pushGenericOverlay({
// title: 'Test Title IMPORTANT',
// description: 'Test Description',
// dismissible: true
// }, true)
}, 5000) }, 5000)
} }
const diff = Date.now() - start const diff = Date.now() - start

View File

@ -42,6 +42,8 @@ class Overlay extends React.Component<OverlayProps> {
<> <>
<ServerSelectOverlay <ServerSelectOverlay
servers={action.payload.servers} servers={action.payload.servers}
selectedId={action.payload.selectedId}
onSelection={action.payload.onSelection}
/> />
</> </>
) )

View File

@ -1,13 +1,86 @@
import * as React from 'react' import * as React from 'react'
import { connect } from 'react-redux'
import { HeliosServer } from 'common/distribution/DistributionFactory'
import { LoggerUtil } from 'common/logging/loggerutil'
import { OverlayActionDispatch } from '../../../redux/actions/overlayActions'
import '../shared-select/SharedSelect.css' import '../shared-select/SharedSelect.css'
import { Server } from 'helios-distribution-types'
export interface ServerSelectOverlayProps { export interface ServerSelectOverlayProps {
servers: Server[] servers: HeliosServer[]
selectedId: string
onSelection: (serverId: string) => void
} }
export default class ServerSelectOverlay extends React.Component<ServerSelectOverlayProps> { interface ServerSelectOverlayState {
selectedId: string
}
const mapDispatch = {
...OverlayActionDispatch
}
type InternalServerSelectOverlayProps = ServerSelectOverlayProps & typeof mapDispatch
class ServerSelectOverlay extends React.Component<InternalServerSelectOverlayProps, ServerSelectOverlayState> {
private readonly logger = LoggerUtil.getLogger('ServerSelectOverlay')
constructor(props: InternalServerSelectOverlayProps) {
super(props)
this.state = {
selectedId: props.selectedId
}
}
private onSelectClick = async (): Promise<void> => {
try {
this.props.onSelection(this.state.selectedId)
} catch(err) {
this.logger.error('Uncaught error in server select confirmation.', err)
}
this.props.popOverlayContent()
}
private onCancelClick = async (): Promise<void> => {
this.props.popOverlayContent()
}
getMainServerStar(): JSX.Element {
return (
<div className="serverListingStarWrapper">
<svg id="mainServerSVG" viewBox="0 0 107.45 104.74" width="20px" height="20px">
<path fill="#fff" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/>
<circle fill="none" stroke="#fff" strokeMiterlimit="10" cx="53.73" cy="53.9" r="38"/>
</svg>
<span className="serverListingStarTooltip">Main Server</span>
</div>
)
}
getServers(): JSX.Element[] {
const servers: JSX.Element[] = []
for(const { rawServer: raw } of this.props.servers) {
servers.push(
<button onClick={() => this.setState({...this.state, selectedId: raw.id})} className="serverListing" {...(raw.id === this.state.selectedId ? {selectedserver: 'true'} : {})} {...{key: raw.id}}>
<img className="serverListingImg" src={raw.icon}/>
<div className="serverListingDetails">
<span className="serverListingName">{raw.name}</span>
<span className="serverListingDescription">{raw.description}</span>
<div className="serverListingInfo">
<div className="serverListingVersion">{raw.minecraftVersion}</div>
<div className="serverListingRevision">{raw.version}</div>
{raw.mainServer ? this.getMainServerStar() : ''}
</div>
</div>
</button>
)
}
return servers
}
render(): JSX.Element { render(): JSX.Element {
return ( return (
@ -16,13 +89,13 @@ export default class ServerSelectOverlay extends React.Component<ServerSelectOve
<span id="serverSelectHeader">Available Servers</span> <span id="serverSelectHeader">Available Servers</span>
<div id="serverSelectList"> <div id="serverSelectList">
<div id="serverSelectListScrollable"> <div id="serverSelectListScrollable">
{/* Server listings populated here. */} {this.getServers()}
</div> </div>
</div> </div>
<div id="serverSelectActions"> <div id="serverSelectActions">
<button id="serverSelectConfirm" className="overlayKeybindEnter" type="submit">Select</button> <button onClick={this.onSelectClick} id="serverSelectConfirm" className="overlayKeybindEnter" type="submit">Select</button>
<div id="serverSelectCancelWrapper"> <div id="serverSelectCancelWrapper">
<button id="serverSelectCancel" className="overlayKeybindEsc">Cancel</button> <button onClick={this.onCancelClick} id="serverSelectCancel" className="overlayKeybindEsc">Cancel</button>
</div> </div>
</div> </div>
</div> </div>
@ -31,3 +104,5 @@ export default class ServerSelectOverlay extends React.Component<ServerSelectOve
} }
} }
export default connect<unknown, typeof mapDispatch>(undefined, mapDispatch)(ServerSelectOverlay)

View File

@ -68,7 +68,7 @@
position: relative; position: relative;
background: rgba(131, 131, 131, 0.25); background: rgba(131, 131, 131, 0.25);
} }
.serverListing[selected] { .serverListing[selectedserver] {
cursor: default; cursor: default;
opacity: 1.0; opacity: 1.0;
} }

View File

@ -28,6 +28,7 @@ ReactDOM.render(
<Application <Application
currentView={store.getState().currentView} currentView={store.getState().currentView}
overlayQueue={store.getState().overlayQueue} overlayQueue={store.getState().overlayQueue}
distribution={store.getState().app.distribution!}
/> />
</Provider> </Provider>
</AppContainer>, </AppContainer>,