mirror of
https://github.com/amineo/t2-stat-parser.git
synced 2026-01-19 17:34:43 +00:00
Deprecated webapp (old stats stack)
This commit is contained in:
parent
aed14743e6
commit
c1fcb61731
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"macros",
|
|
||||||
"@babel/plugin-proposal-class-properties"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
12
app/webapp/.gitignore
vendored
12
app/webapp/.gitignore
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
# Adonis directory for storing tmp files
|
|
||||||
tmp
|
|
||||||
|
|
||||||
# Don't store build
|
|
||||||
build
|
|
||||||
|
|
||||||
# Environment variables, never commit this file
|
|
||||||
.env
|
|
||||||
|
|
||||||
public/hot
|
|
||||||
public/mix-manifest.json
|
|
||||||
public/dist
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
# Adonis Slim App
|
|
||||||
|
|
||||||
The Adonis slim app is the tinest boilerplate to create Adonisjs applications with minimal footprint and you get all the goodies of Adonis IoC container, autoloading, ace commands etc.
|
|
||||||
|
|
||||||
## What's next?
|
|
||||||
|
|
||||||
This project structure can scale as you go, simply execute the `ace` commands to create **Controllers**, **Models**, etc for you.
|
|
||||||
|
|
||||||
Also make sure to read the [guides](http://dev.adonisjs.com/docs/4.0/installation)
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Ace Commands
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The ace file is just a regular Javascript file but with no extension. You
|
|
||||||
| can call `node ace` followed by the command name and it just works.
|
|
||||||
|
|
|
||||||
| Also you can use `adonis` followed by the command name, since the adonis
|
|
||||||
| global proxy all the ace commands.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { Ignitor } = require('@adonisjs/ignitor')
|
|
||||||
|
|
||||||
new Ignitor(require('@adonisjs/fold'))
|
|
||||||
.appRoot(__dirname)
|
|
||||||
.fireAce()
|
|
||||||
.catch(console.error)
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const Database = use('Database');
|
|
||||||
|
|
||||||
class GameController {
|
|
||||||
// /games
|
|
||||||
async index({ inertia }) {
|
|
||||||
const pageTitle = `Latest Games`;
|
|
||||||
|
|
||||||
// const gamesQry = await Database.raw(`
|
|
||||||
// SELECT distinct game_id,map,gametype, datestamp
|
|
||||||
// FROM games
|
|
||||||
// WHERE (stats->>'score' IS NOT NULL) AND (game_id <> 0)
|
|
||||||
// ORDER BY game_id desc
|
|
||||||
// LIMIT 2000;
|
|
||||||
// `);
|
|
||||||
|
|
||||||
// const gamesQry = await Database.raw(`
|
|
||||||
// WITH gamelist AS (
|
|
||||||
// SELECT DISTINCT p.game_id, p.map, p.gametype, p.datestamp, count(*) OVER (PARTITION BY game_id) as count from games p
|
|
||||||
// )
|
|
||||||
// SELECT * from gamelist
|
|
||||||
// WHERE (count > 1) AND (game_id <> 0)
|
|
||||||
// ORDER BY game_id desc
|
|
||||||
// LIMIT 2000
|
|
||||||
// `);
|
|
||||||
|
|
||||||
// // filter out duplicate game_ids (https://dev.to/marinamosti/removing-duplicates-in-an-array-of-objects-in-js-with-sets-3fep)
|
|
||||||
// const games = gamesQry.rows.reduce((game, current) => {
|
|
||||||
|
|
||||||
// const x = game.find(item => item.game_id === current.game_id);
|
|
||||||
// if (!x) {
|
|
||||||
// return game.concat([current]);
|
|
||||||
// } else {
|
|
||||||
// return game;
|
|
||||||
// }
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
const games = await Database.from('games').orderBy('game_id', 'desc').limit(200);
|
|
||||||
// const CTFgames = await Database.from('games').where({gametype: 'CTFGame'}).orderBy('game_id', 'desc').limit(120);
|
|
||||||
// const LAKgames = await Database.from('games').where({gametype: 'LakRabbitGame'}).orderBy('game_id', 'desc').limit(120);
|
|
||||||
|
|
||||||
// move the 0 score display logic here
|
|
||||||
|
|
||||||
return inertia.render('Games/Main', { pageTitle, games }, { edgeVar: 'server-variable' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// game/:game_id
|
|
||||||
async game({ inertia, request }) {
|
|
||||||
const gameInfo = await Database.from('game_detail')
|
|
||||||
.select('game_id', 'map', 'player_name', 'player_guid', 'gametype', 'stats', 'datestamp')
|
|
||||||
.where({ game_id: request.params.game_id })
|
|
||||||
.orderByRaw("stats->>'scoreTG' desc");
|
|
||||||
|
|
||||||
const pageTitle = {
|
|
||||||
name: gameInfo[0]['map'],
|
|
||||||
gametype: gameInfo[0]['gametype']
|
|
||||||
};
|
|
||||||
|
|
||||||
return inertia.render('Games/Game', { pageTitle, gameInfo }, { edgeVar: 'server-variable' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = GameController;
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
class IndexController {
|
|
||||||
|
|
||||||
index({ inertia }) {
|
|
||||||
const pageTitle = "Home!"
|
|
||||||
return inertia.render('Index', { pageTitle }, { edgeVar: 'server-variable' })
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = IndexController
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const Database = use('Database');
|
|
||||||
|
|
||||||
class PlayerController {
|
|
||||||
// Main Players List
|
|
||||||
async index({ inertia }) {
|
|
||||||
const pageTitle = 'All Players';
|
|
||||||
const players = await Database.table('players')
|
|
||||||
.distinct(
|
|
||||||
'player_guid',
|
|
||||||
'player_name',
|
|
||||||
'total_games_ctfgame',
|
|
||||||
'total_games_dmgame',
|
|
||||||
'total_games_lakrabbitgame',
|
|
||||||
'total_games_sctfgame',
|
|
||||||
'updated_at'
|
|
||||||
)
|
|
||||||
.groupBy('player_guid')
|
|
||||||
.orderBy('player_name', 'asc')
|
|
||||||
.limit(1000);
|
|
||||||
|
|
||||||
return inertia.render('Players/Main', { pageTitle, players }, { edgeVar: 'server-variable' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Player Detail
|
|
||||||
async player({ inertia, request }) {
|
|
||||||
const playerInfo = await Database.from('players')
|
|
||||||
.distinct(
|
|
||||||
'player_guid',
|
|
||||||
'player_name',
|
|
||||||
'total_games_ctfgame',
|
|
||||||
'total_games_dmgame',
|
|
||||||
'total_games_lakrabbitgame',
|
|
||||||
'total_games_sctfgame'
|
|
||||||
)
|
|
||||||
.where({ player_guid: request.params.player_guid })
|
|
||||||
.limit(50);
|
|
||||||
|
|
||||||
const playerStatData = await Database.from('game_detail')
|
|
||||||
.select('game_id', 'gametype', 'stats')
|
|
||||||
.where({ player_guid: request.params.player_guid })
|
|
||||||
.orderBy('game_id', 'desc')
|
|
||||||
.limit(50);
|
|
||||||
|
|
||||||
// Dynamically generate and sum the stats object
|
|
||||||
let playerStatTotals = {},
|
|
||||||
statKeys = Object.keys(playerStatData[0].stats);
|
|
||||||
|
|
||||||
for (let i = 0; i < statKeys.length; i++) {
|
|
||||||
if (statKeys[i] === 'map' || statKeys[i] === 'dateStamp' || statKeys[i] === 'timeDayMonth') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
playerStatTotals[statKeys[i]] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through the playerStatsData query from the DB
|
|
||||||
playerStatData.map((statLine) => {
|
|
||||||
// look through each object in playerStatsData array
|
|
||||||
for (let [ key, value ] of Object.entries(statLine.stats)) {
|
|
||||||
// console.log(`${key}: ${value}`);
|
|
||||||
// If the stat item exists, add it -- if not create a new key in playerStatTotals
|
|
||||||
if (playerStatTotals.hasOwnProperty(key) === true) {
|
|
||||||
playerStatTotals[key] = playerStatTotals[key] + Number(value);
|
|
||||||
} else {
|
|
||||||
playerStatTotals[key] = Number(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let playerData = {
|
|
||||||
player: playerInfo[0],
|
|
||||||
stats: playerStatData,
|
|
||||||
totals: playerStatTotals
|
|
||||||
};
|
|
||||||
|
|
||||||
const pageTitle = playerData.player.player_name;
|
|
||||||
return inertia.render('Players/Player', { pageTitle, playerData }, { edgeVar: 'server-variable' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = PlayerController;
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// babel-plugin-macros.config.js
|
|
||||||
module.exports = {
|
|
||||||
twin: {
|
|
||||||
config: './tailwind.config.js',
|
|
||||||
styled: '@emotion/styled',
|
|
||||||
format: 'auto',
|
|
||||||
hasSuggestions: true,
|
|
||||||
debug: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,243 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/** @type {import('@adonisjs/framework/src/Env')} */
|
|
||||||
const Env = use('Env')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application Name
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This value is the name of your application and can used when you
|
|
||||||
| need to place the application's name in a email, view or
|
|
||||||
| other location.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
name: Env.get('APP_NAME', 'AdonisJs'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| App Key
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| App key is a randomly generated 16 or 32 characters long string required
|
|
||||||
| to encrypted cookies, sessions and other sensitive data.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
appKey: Env.getOrFail('APP_KEY'),
|
|
||||||
|
|
||||||
http: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Allow Method Spoofing
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Method spoofing allows to make requests by spoofing the http verb.
|
|
||||||
| Which means you can make a GET request but instruct the server to
|
|
||||||
| treat as a POST or PUT request. If you want this feature, set the
|
|
||||||
| below value to true.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
allowMethodSpoofing: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Trust Proxy
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Trust proxy defines whether X-Forwaded-* headers should be trusted or not.
|
|
||||||
| When your application is behind a proxy server like nginx, these values
|
|
||||||
| are set automatically and should be trusted. Apart from setting it
|
|
||||||
| to true or false Adonis supports handful or ways to allow proxy
|
|
||||||
| values. Read documentation for that.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
trustProxy: false,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Subdomains
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Offset to be used for returning subdomains for a given request.For
|
|
||||||
| majority of applications it will be 2, until you have nested
|
|
||||||
| sudomains.
|
|
||||||
| cheatsheet.adonisjs.com - offset - 2
|
|
||||||
| virk.cheatsheet.adonisjs.com - offset - 3
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
subdomainOffset: 2,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| JSONP Callback
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Default jsonp callback to be used when callback query string is missing
|
|
||||||
| in request url.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
jsonpCallback: 'callback',
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Etag
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Set etag on all HTTP response. In order to disable for selected routes,
|
|
||||||
| you can call the `response.send` with an options object as follows.
|
|
||||||
|
|
|
||||||
| response.send('Hello', { ignoreEtag: true })
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
etag: false
|
|
||||||
},
|
|
||||||
|
|
||||||
views: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Cache Views
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define whether or not to cache the compiled view. Set it to true in
|
|
||||||
| production to optimize view loading time.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
cache: Env.get('CACHE_VIEWS', true)
|
|
||||||
},
|
|
||||||
|
|
||||||
static: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Dot Files
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define how to treat dot files when trying to server static resources.
|
|
||||||
| By default it is set to ignore, which will pretend that dotfiles
|
|
||||||
| does not exists.
|
|
||||||
|
|
|
||||||
| Can be one of the following
|
|
||||||
| ignore, deny, allow
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
dotfiles: 'ignore',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| ETag
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enable or disable etag generation
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
etag: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Extensions
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Set file extension fallbacks. When set, if a file is not found, the given
|
|
||||||
| extensions will be added to the file name and search for. The first
|
|
||||||
| that exists will be served. Example: ['html', 'htm'].
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
extensions: false
|
|
||||||
},
|
|
||||||
|
|
||||||
locales: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Loader
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The loader to be used for fetching and updating locales. Below is the
|
|
||||||
| list of available options.
|
|
||||||
|
|
|
||||||
| file, database
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
loader: 'file',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Default Locale
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Default locale to be used by Antl provider. You can always switch drivers
|
|
||||||
| in runtime or use the official Antl middleware to detect the driver
|
|
||||||
| based on HTTP headers/query string.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
locale: 'en'
|
|
||||||
},
|
|
||||||
|
|
||||||
logger: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Transport
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Transport to be used for logging messages. You can have multiple
|
|
||||||
| transports using same driver.
|
|
||||||
|
|
|
||||||
| Available drivers are: `file` and `console`.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
transport: 'console',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Console Transport
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Using `console` driver for logging. This driver writes to `stdout`
|
|
||||||
| and `stderr`
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
console: {
|
|
||||||
driver: 'console',
|
|
||||||
name: 'adonis-app',
|
|
||||||
level: 'info'
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| File Transport
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| File transport uses file driver and writes log messages for a given
|
|
||||||
| file inside `tmp` directory for your app.
|
|
||||||
|
|
|
||||||
| For a different directory, set an absolute path for the filename.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
file: {
|
|
||||||
driver: 'file',
|
|
||||||
name: 'adonis-app',
|
|
||||||
filename: 'adonis.log',
|
|
||||||
level: 'info'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Generic Cookie Options
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The following cookie options are generic settings used by AdonisJs to create
|
|
||||||
| cookies. However, some parts of the application like `sessions` can have
|
|
||||||
| seperate settings for cookies inside `config/session.js`.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
cookie: {
|
|
||||||
httpOnly: true,
|
|
||||||
sameSite: false,
|
|
||||||
path: '/',
|
|
||||||
maxAge: 7200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| JSON Parser
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Below settings are applied when the request body contains a JSON payload.
|
|
||||||
| If you want body parser to ignore JSON payloads, then simply set `types`
|
|
||||||
| to an empty array.
|
|
||||||
*/
|
|
||||||
json: {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| limit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Defines the limit of JSON that can be sent by the client. If payload
|
|
||||||
| is over 1mb it will not be processed.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
limit: '1mb',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| strict
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| When `strict` is set to true, body parser will only parse Arrays and
|
|
||||||
| Object. Otherwise everything parseable by `JSON.parse` is parsed.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
strict: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| types
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Which content types are processed as JSON payloads. You are free to
|
|
||||||
| add your own types here, but the request body should be parseable
|
|
||||||
| by `JSON.parse` method.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
types: [
|
|
||||||
'application/json',
|
|
||||||
'application/json-patch+json',
|
|
||||||
'application/vnd.api+json',
|
|
||||||
'application/csp-report'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Raw Parser
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
raw: {
|
|
||||||
types: [
|
|
||||||
'text/*'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Form Parser
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
form: {
|
|
||||||
types: [
|
|
||||||
'application/x-www-form-urlencoded'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Files Parser
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
files: {
|
|
||||||
types: [
|
|
||||||
'multipart/form-data'
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Max Size
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Below value is the max size of all the files uploaded to the server. It
|
|
||||||
| is validated even before files have been processed and hard exception
|
|
||||||
| is thrown.
|
|
||||||
|
|
|
||||||
| Consider setting a reasonable value here, otherwise people may upload GB's
|
|
||||||
| of files which will keep your server busy.
|
|
||||||
|
|
|
||||||
| Also this value is considered when `autoProcess` is set to true.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
maxSize: '20mb',
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Auto Process
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Whether or not to auto-process files. Since HTTP servers handle files via
|
|
||||||
| couple of specific endpoints. It is better to set this value off and
|
|
||||||
| manually process the files when required.
|
|
||||||
|
|
|
||||||
| This value can contain a boolean or an array of route patterns
|
|
||||||
| to be autoprocessed.
|
|
||||||
*/
|
|
||||||
autoProcess: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Process Manually
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The list of routes that should not process files and instead rely on
|
|
||||||
| manual process. This list should only contain routes when autoProcess
|
|
||||||
| is to true. Otherwise everything is processed manually.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
processManually: []
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Temporary file name
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define a function, which should return a string to be used as the
|
|
||||||
| tmp file name.
|
|
||||||
|
|
|
||||||
| If not defined, Bodyparser will use `uuid` as the tmp file name.
|
|
||||||
|
|
|
||||||
| To be defined as. If you are defining the function, then do make sure
|
|
||||||
| to return a value from it.
|
|
||||||
|
|
|
||||||
| tmpFileName () {
|
|
||||||
| return 'some-unique-value'
|
|
||||||
| }
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Origin
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Set a list of origins to be allowed. The value can be one of the following
|
|
||||||
|
|
|
||||||
| Boolean: true - Allow current request origin
|
|
||||||
| Boolean: false - Disallow all
|
|
||||||
| String - Comma seperated list of allowed origins
|
|
||||||
| Array - An array of allowed origins
|
|
||||||
| String: * - A wildcard to allow current request origin
|
|
||||||
| Function - Receives the current origin and should return one of the above values.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
origin: ['playt2.com'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Methods
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| HTTP methods to be allowed. The value can be one of the following
|
|
||||||
|
|
|
||||||
| String - Comma seperated list of allowed methods
|
|
||||||
| Array - An array of allowed methods
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
methods: ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Headers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| List of headers to be allowed via Access-Control-Request-Headers header.
|
|
||||||
| The value can be on of the following.
|
|
||||||
|
|
|
||||||
| Boolean: true - Allow current request headers
|
|
||||||
| Boolean: false - Disallow all
|
|
||||||
| String - Comma seperated list of allowed headers
|
|
||||||
| Array - An array of allowed headers
|
|
||||||
| String: * - A wildcard to allow current request headers
|
|
||||||
| Function - Receives the current header and should return one of the above values.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
headers: true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Expose Headers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| A list of headers to be exposed via `Access-Control-Expose-Headers`
|
|
||||||
| header. The value can be on of the following.
|
|
||||||
|
|
|
||||||
| Boolean: false - Disallow all
|
|
||||||
| String: Comma seperated list of allowed headers
|
|
||||||
| Array - An array of allowed headers
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
exposeHeaders: false,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Credentials
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define Access-Control-Allow-Credentials header. It should always be a
|
|
||||||
| boolean.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
credentials: false,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| MaxAge
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Define Access-Control-Max-Age
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
maxAge: 90
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/** @type {import('@adonisjs/framework/src/Env')} */
|
|
||||||
const Env = use('Env')
|
|
||||||
|
|
||||||
/** @type {import('@adonisjs/ignitor/src/Helpers')} */
|
|
||||||
const Helpers = use('Helpers')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Default Connection
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Connection defines the default connection settings to be used while
|
|
||||||
| interacting with SQL databases.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
connection: Env.get('DB_CONNECTION', 'pg'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| PostgreSQL
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here we define connection settings for PostgreSQL database.
|
|
||||||
|
|
|
||||||
| npm i --save pg
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
pg: {
|
|
||||||
client: 'pg',
|
|
||||||
connection: {
|
|
||||||
host: Env.get('DB_HOST', 'localhost'),
|
|
||||||
port: Env.get('DB_PORT', ''),
|
|
||||||
user: Env.get('DB_USER', 'root'),
|
|
||||||
password: Env.get('DB_PASSWORD', ''),
|
|
||||||
database: Env.get('DB_DATABASE', 'adonis')
|
|
||||||
},
|
|
||||||
pool: { min: 0, max: 10 },
|
|
||||||
debug: Env.get('DB_DEBUG', false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/** @type {import('@adonisjs/framework/src/Env')} */
|
|
||||||
const Env = use('Env')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Driver
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Driver to be used for hashing values. The same driver is used by the
|
|
||||||
| auth module too.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
driver: Env.get('HASH_DRIVER', 'bcrypt'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Bcrypt
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Config related to bcrypt hashing. https://www.npmjs.com/package/bcrypt
|
|
||||||
| package is used internally.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
bcrypt: {
|
|
||||||
rounds: 10
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Argon
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Config related to argon. https://www.npmjs.com/package/argon2 package is
|
|
||||||
| used internally.
|
|
||||||
|
|
|
||||||
| Since argon is optional, you will have to install the dependency yourself
|
|
||||||
|
|
|
||||||
|============================================================================
|
|
||||||
| npm i argon2
|
|
||||||
|============================================================================
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
argon: {
|
|
||||||
type: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
apps : [{
|
|
||||||
name: process.env.APP_NAME,
|
|
||||||
script: 'server.js',
|
|
||||||
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
|
||||||
instances: 1,
|
|
||||||
autorestart: true,
|
|
||||||
watch: true,
|
|
||||||
ignore_watch:['node_modules','public','resources/js','resources/scss']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: process.env.APP_NAME + '_react',
|
|
||||||
script: 'node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js "--watch"',
|
|
||||||
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
|
||||||
instances: 1,
|
|
||||||
autorestart: false,
|
|
||||||
watch: false,
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
apps : [{
|
|
||||||
name: process.env.APP_NAME,
|
|
||||||
script: 'server.js',
|
|
||||||
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
|
||||||
instances: 1,
|
|
||||||
autorestart: true,
|
|
||||||
watch: true,
|
|
||||||
ignore_watch:['node_modules','public','resources/js','resources/scss']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: process.env.APP_NAME + '_react_hot',
|
|
||||||
script: 'node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js',
|
|
||||||
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
|
||||||
instances: 1,
|
|
||||||
autorestart: false,
|
|
||||||
watch: false,
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
apps: [
|
|
||||||
{
|
|
||||||
name: process.env.APP_NAME,
|
|
||||||
script: 'server.js',
|
|
||||||
autorestart: true,
|
|
||||||
instances: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
20161
app/webapp/package-lock.json
generated
20161
app/webapp/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,80 +0,0 @@
|
||||||
{
|
|
||||||
"name": "adonis-inertia-react-starter",
|
|
||||||
"version": "4.1.0",
|
|
||||||
"adonis-version": "4.1.0",
|
|
||||||
"description": "Adonis, Inertia, React, Emotion, TailwindCSS, Webpack Mix, PostCSS",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"start": "node server.js",
|
|
||||||
"test": "node ace test",
|
|
||||||
"webpack-server": "/opt/node_modules/webpack/bin/webpack.js --progress --hide-modules --config=/opt/node_modules/laravel-mix/setup/webpack.config.js",
|
|
||||||
"watch": "npm run webpack-server -- --watch"
|
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"extends": "react-app"
|
|
||||||
},
|
|
||||||
"browserslist": {
|
|
||||||
"production": [
|
|
||||||
">0.2%",
|
|
||||||
"not dead",
|
|
||||||
"not op_mini all"
|
|
||||||
],
|
|
||||||
"development": [
|
|
||||||
"last 1 chrome version",
|
|
||||||
"last 1 firefox version",
|
|
||||||
"last 1 safari version"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"adonisjs",
|
|
||||||
"adonis-app",
|
|
||||||
"inertajs",
|
|
||||||
"react"
|
|
||||||
],
|
|
||||||
"author": "",
|
|
||||||
"license": "UNLICENSED",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@adonisjs/ace": "^5.0.8",
|
|
||||||
"@adonisjs/bodyparser": "^2.0.9",
|
|
||||||
"@adonisjs/cors": "^1.0.7",
|
|
||||||
"@adonisjs/fold": "^4.0.9",
|
|
||||||
"@adonisjs/framework": "^5.0.9",
|
|
||||||
"@adonisjs/ignitor": "^2.0.8",
|
|
||||||
"@adonisjs/lucid": "^6.1.3",
|
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
||||||
"@inertiajs/inertia": "^0.1.7",
|
|
||||||
"@inertiajs/inertia-react": "^0.1.4",
|
|
||||||
"@tailwindcss/ui": "^0.1.3",
|
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
|
||||||
"@testing-library/react": "^9.3.2",
|
|
||||||
"@testing-library/user-event": "^7.1.2",
|
|
||||||
"inertia-adonis": "^0.1.2",
|
|
||||||
"node-cookie": "^2.1.2",
|
|
||||||
"pg": "^7.18.2",
|
|
||||||
"react": "^16.13.0",
|
|
||||||
"react-dom": "^16.13.0",
|
|
||||||
"react-scripts": "3.4.0",
|
|
||||||
"recharts": "^1.8.5",
|
|
||||||
"tailwindcss": "^1.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
|
||||||
"@babel/plugin-transform-react-jsx": "^7.9.1",
|
|
||||||
"@babel/preset-react": "^7.9.1",
|
|
||||||
"@emotion/core": "^10.0.28",
|
|
||||||
"@emotion/styled": "^10.0.27",
|
|
||||||
"autoprefixer": "^9.7.4",
|
|
||||||
"babel-plugin-macros": "^2.8.0",
|
|
||||||
"laravel-mix": "^5.0.4",
|
|
||||||
"laravel-mix-purgecss": "^5.0.0-rc.1",
|
|
||||||
"laravel-mix-tailwind": "^0.1.0",
|
|
||||||
"postcss-cli": "^7.1.0",
|
|
||||||
"postcss-loader": "^3.0.0",
|
|
||||||
"sass": "^1.26.3",
|
|
||||||
"twin.macro": "^1.0.0-alpha.7"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"App": "./app"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?><svg width="36px" height="33px" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g transform="translate(0 .5)" fill="none" fill-rule="evenodd"><path d="M20 2.236L5.618 31h28.764L20 2.236z" stroke="#FFFFFF" stroke-width="2"/><path fill="#FFFFFF" d="M12 2l12 24H0"/></g></svg>
|
|
||||||
|
Before Width: | Height: | Size: 363 B |
Binary file not shown.
|
Before Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
|
|
@ -1 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?><svg width="186px" height="31px" viewBox="0 0 186 31" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M20.25 6.106V.1H.72v6.006h5.712v17.388H.72V29.5h19.53v-6.006h-5.712V6.106h5.712zm18.774 7.35v-5.46h-6.846V1.528h-7.182v3.108c0 2.226-1.218 3.36-3.444 3.36h-.084v5.46h3.528v8.904c0 4.578 3.528 7.686 8.82 7.686 1.932 0 3.276-.126 5.208-1.05v-5.964c-2.016.882-2.982.966-3.822.966-1.806 0-3.024-1.008-3.024-2.898v-7.644h6.846zm37.17-5.46l-3.612 13.692L68.76 7.996H63.3l-3.822 13.692-3.654-13.692h-7.308L55.068 29.5h7.266l3.696-12.516L69.684 29.5h7.308l6.552-21.504h-7.35zM95.43 7.45c6.846 0 11.424 4.746 11.424 11.256 0 6.552-4.578 11.34-11.424 11.34-6.888 0-11.466-4.788-11.466-11.34 0-6.51 4.578-11.256 11.466-11.256zm0 5.628c-2.898 0-4.62 2.352-4.62 5.628 0 3.318 1.722 5.712 4.62 5.712 2.856 0 4.578-2.394 4.578-5.712 0-3.276-1.722-5.628-4.578-5.628zm22.092.714V7.996h-7.182V29.5h7.182v-7.518c0-5.376 1.89-7.728 8.946-6.972V7.534c-4.788 0-7.686 1.806-8.946 6.258zM145.158 29.5h8.4l-7.812-11.886 7.14-9.618h-8.316l-4.284 6.552h-3.612V.1h-7.182v29.4h7.182v-8.442h3.612l4.872 8.442zm22.092-14.196h6.384c-.462-5.46-4.326-7.854-9.87-7.854-6.09 0-9.534 2.436-9.534 6.804 0 4.998 4.494 5.586 8.19 6.426 3.822.882 4.704 1.134 4.704 2.478 0 1.512-1.428 1.932-2.982 1.932-2.394 0-3.822-.966-4.074-3.486h-6.384c.336 5.88 4.536 8.442 10.542 8.442 6.132 0 9.66-2.688 9.66-7.14 0-4.998-4.41-5.628-8.736-6.594-3.234-.672-4.326-.882-4.326-2.31 0-1.134 1.176-1.848 2.856-1.848 2.268 0 3.276.882 3.57 3.15zm11.424 4.536h6.258L185.94.1h-8.316l1.05 19.74zm-.63 9.66h7.518v-6.51h-7.518v6.51z" fill="#FFFFFF" fill-rule="evenodd"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -1,16 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const FrameHeading = (props) => {
|
|
||||||
return (
|
|
||||||
<header className="bg-white shadow-sm">
|
|
||||||
<div className="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8">
|
|
||||||
<h1 className="text-lg leading-6 font-semibold text-gray-900">
|
|
||||||
{props.heading}
|
|
||||||
</h1>
|
|
||||||
{ props.gametype ? props.gametype : ''}
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FrameHeading;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './FrameHeading';
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const returnTotalSumGames = (player) => {
|
|
||||||
let sum = Number(player.ctf) +
|
|
||||||
Number(player.dm) +
|
|
||||||
Number(player.lak) +
|
|
||||||
Number(player.spawnctf);
|
|
||||||
return sum
|
|
||||||
};
|
|
||||||
|
|
||||||
const GameTypesPlayedBoxes = (props) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h3 className="text-md leading-6 font-medium text-gray-900">
|
|
||||||
Games Played {returnTotalSumGames(props)}
|
|
||||||
</h3>
|
|
||||||
<div className="mt-5 grid grid-cols-1 gap-5 sm:grid-cols-4">
|
|
||||||
<div className="bg-white overflow-hidden shadow rounded-lg">
|
|
||||||
<div className="px-4 py-5 sm:p-6">
|
|
||||||
<dl>
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
|
||||||
Capture the Flag
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
|
||||||
{props.ctf}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white overflow-hidden shadow rounded-lg">
|
|
||||||
<div className="px-4 py-5 sm:p-6">
|
|
||||||
<dl>
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
|
||||||
LAK Rabbit
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
|
||||||
{props.lak}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white overflow-hidden shadow rounded-lg">
|
|
||||||
<div className="px-4 py-5 sm:p-6">
|
|
||||||
<dl>
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
|
||||||
Spawn CTF
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
|
||||||
{props.spawnctf}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white overflow-hidden shadow rounded-lg">
|
|
||||||
<div className="px-4 py-5 sm:p-6">
|
|
||||||
<dl>
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
|
||||||
Deathmatch
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
|
||||||
{props.dm}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GameTypesPlayedBoxes;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './GameTypesPlayedBoxes';
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const returnTotalSumGames = (player) => {
|
|
||||||
let sum = Number(player.ctf) +
|
|
||||||
Number(player.dm) +
|
|
||||||
Number(player.lak) +
|
|
||||||
Number(player.spawnctf);
|
|
||||||
return sum
|
|
||||||
};
|
|
||||||
|
|
||||||
const GameTypesPlayedCols = (props) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<dl className="grid grid-cols-1 col-gap-4 row-gap-8 sm:grid-cols-4">
|
|
||||||
<div className="sm:col-span-1">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">
|
|
||||||
CTF
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{props.ctf} </span>
|
|
||||||
</dd>
|
|
||||||
</div><div className="sm:col-span-1">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">
|
|
||||||
LAK Rabbit
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{props.lak}</span>
|
|
||||||
</dd>
|
|
||||||
</div><div className="sm:col-span-1">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">
|
|
||||||
Spawn CTF
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{props.spawnctf}</span>
|
|
||||||
</dd>
|
|
||||||
</div><div className="sm:col-span-1">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">
|
|
||||||
Deathmatch
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{props.dm}</span>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
<div className="mt-5">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">
|
|
||||||
Total
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{returnTotalSumGames(props)}</span>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GameTypesPlayedCols;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './GameTypesPlayedCols';
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { InertiaLink } from '@inertiajs/inertia-react'
|
|
||||||
|
|
||||||
|
|
||||||
const navItems = () =>
|
|
||||||
<div className="ml-10 flex items-baseline">
|
|
||||||
{/* <InertiaLink href="/" className="px-3 py-2 rounded-md text-sm font-medium text-white bg-gray-900 focus:outline-none focus:text-white focus:bg-gray-700">Home</InertiaLink> */}
|
|
||||||
<InertiaLink href="/games" className="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Games</InertiaLink>
|
|
||||||
<InertiaLink href="/players" className="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Players</InertiaLink>
|
|
||||||
</div>;
|
|
||||||
|
|
||||||
const TopNav = () => {
|
|
||||||
return (
|
|
||||||
<nav className="bg-gray-800">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<div className="flex items-center justify-between h-16">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<div className="flex-shrink-0">
|
|
||||||
<img className="h-8 w-8" src="https://d33wubrfki0l68.cloudfront.net/1699fc97aa9b1cb851a6c0039162a9241724e1fb/7289f/images/logo.png" alt="Tribes 2 Stats" />
|
|
||||||
</div>
|
|
||||||
<div className="md:block">
|
|
||||||
{ navItems() }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="md:block">
|
|
||||||
<div className="ml-4 flex items-center md:ml-6">
|
|
||||||
<span className="inline-flex rounded-md shadow-sm">
|
|
||||||
<a href="https://www.playt2.com/discord" className="inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
|
|
||||||
Join Discord
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TopNav;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './TopNav';
|
|
||||||
|
|
@ -1,171 +0,0 @@
|
||||||
import React, { PureComponent } from 'react';
|
|
||||||
import { InertiaLink } from '@inertiajs/inertia-react';
|
|
||||||
import Layout from '@/Shared/Layout';
|
|
||||||
|
|
||||||
import { PieChart, Pie, Sector } from 'recharts';
|
|
||||||
|
|
||||||
const renderActiveShape = (props) => {
|
|
||||||
const RADIAN = Math.PI / 180;
|
|
||||||
const { cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent, value } = props;
|
|
||||||
const sin = Math.sin(-RADIAN * midAngle);
|
|
||||||
const cos = Math.cos(-RADIAN * midAngle);
|
|
||||||
const sx = cx + (outerRadius + 10) * cos;
|
|
||||||
const sy = cy + (outerRadius + 10) * sin;
|
|
||||||
const mx = cx + (outerRadius + 30) * cos;
|
|
||||||
const my = cy + (outerRadius + 30) * sin;
|
|
||||||
const ex = mx + (cos >= 0 ? 1 : -1) * 22;
|
|
||||||
const ey = my;
|
|
||||||
const textAnchor = cos >= 0 ? 'start' : 'end';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
<text x={cx} y={cy} dy={8} textAnchor="middle" fill="#5850ec">
|
|
||||||
{payload.name}
|
|
||||||
</text>
|
|
||||||
<Sector
|
|
||||||
cx={cx}
|
|
||||||
cy={cy}
|
|
||||||
innerRadius={innerRadius}
|
|
||||||
outerRadius={outerRadius}
|
|
||||||
startAngle={startAngle}
|
|
||||||
endAngle={endAngle}
|
|
||||||
fill="#8884d8"
|
|
||||||
/>
|
|
||||||
<Sector
|
|
||||||
cx={cx}
|
|
||||||
cy={cy}
|
|
||||||
startAngle={startAngle}
|
|
||||||
endAngle={endAngle}
|
|
||||||
innerRadius={outerRadius + 6}
|
|
||||||
outerRadius={outerRadius + 10}
|
|
||||||
fill="#6761d6"
|
|
||||||
/>
|
|
||||||
<path d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`} stroke={fill} fill="none" />
|
|
||||||
<circle cx={ex} cy={ey} r={2} fill={fill} stroke="none" />
|
|
||||||
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} textAnchor={textAnchor} fill="#333">{`${value}`}</text>
|
|
||||||
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} dy={18} textAnchor={textAnchor} fill="#999">
|
|
||||||
{`(${(percent * 100).toFixed(2)}%)`}
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export class TwoLevelPieChart extends PureComponent {
|
|
||||||
state = {
|
|
||||||
activeIndex: this.props.data.oScore >= this.props.data.dScore ? 0 : 1,
|
|
||||||
data: [ { name: 'Offense', value: this.props.data.oScore }, { name: 'Defense', value: this.props.data.dScore } ]
|
|
||||||
};
|
|
||||||
|
|
||||||
onPieEnter = (data, index) => {
|
|
||||||
this.setState({
|
|
||||||
activeIndex: index
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<PieChart width={400} height={400}>
|
|
||||||
<Pie
|
|
||||||
activeIndex={this.state.activeIndex}
|
|
||||||
activeShape={renderActiveShape}
|
|
||||||
data={this.state.data}
|
|
||||||
cx={200}
|
|
||||||
cy={200}
|
|
||||||
innerRadius={60}
|
|
||||||
outerRadius={80}
|
|
||||||
fill="#ccc"
|
|
||||||
dataKey="value"
|
|
||||||
onMouseEnter={this.onPieEnter}
|
|
||||||
className="text-xs"
|
|
||||||
/>
|
|
||||||
</PieChart>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const PlayerRow = (player, index) => {
|
|
||||||
// dont show scoreless players
|
|
||||||
// if (Number(player.stats.scoreTG) <= 0) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col rounded-lg shadow-lg overflow-hidden" key={index}>
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
|
|
||||||
<div className="px-4 py-5 border-b border-gray-200 sm:px-6">
|
|
||||||
<h3 className="text-lg leading-6 font-medium">
|
|
||||||
<InertiaLink
|
|
||||||
href={`/player/${player.player_guid}`}
|
|
||||||
className="text-indigo-600 hover:text-indigo-500 transition duration-150 ease-in-out"
|
|
||||||
>
|
|
||||||
{player.player_name}
|
|
||||||
</InertiaLink>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<dl>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Total Score</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.scoreTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 flex items-center justify-center">
|
|
||||||
{player.gametype == 'CTFGame' || player.gametype == 'SCtFGame' ? (
|
|
||||||
<TwoLevelPieChart
|
|
||||||
data={{
|
|
||||||
oScore: Number(player.stats.offenseScoreTG[0]),
|
|
||||||
dScore: Number(player.stats.defenseScoreTG[0])
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Kills / Assists</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.killsTG} / {player.stats.assistTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">MAs</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.totalMATG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Flag Grabs / Caps</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.flagGrabsTG} / {player.stats.flagCapsTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">
|
|
||||||
Flag Defends / Capper Kills / Returns
|
|
||||||
</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.flagDefendsTG} / {player.stats.carrierKillsTG} /{' '}
|
|
||||||
{player.stats.flagReturnsTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Game(props) {
|
|
||||||
return (
|
|
||||||
<Layout title={props.pageTitle.name} gametype={props.pageTitle.gametype}>
|
|
||||||
<div className="mt-2 grid gap-5 max-w-lg mx-auto lg:grid-cols-3 lg:max-w-none">
|
|
||||||
{props.gameInfo.map((game, index) => PlayerRow(game, index))}
|
|
||||||
</div>
|
|
||||||
{/*
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-md">
|
|
||||||
<div className="py-10 px-10"><code> {JSON.stringify(props.gameInfo)}</code></div>
|
|
||||||
</div> */}
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { InertiaLink } from '@inertiajs/inertia-react'
|
|
||||||
import Layout from '@/Shared/Layout'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const GameRow = (game, index) => {
|
|
||||||
|
|
||||||
return <li key={index}>
|
|
||||||
<InertiaLink href={`/game/${game.game_id}`} className="block hover:bg-gray-50 focus:outline-none focus:bg-gray-50 transition duration-150 ease-in-out">
|
|
||||||
<div className="flex items-center px-4 py-4 sm:px-6">
|
|
||||||
<div className="min-w-0 flex-1 flex items-center">
|
|
||||||
<div className="min-w-0 flex-1 md:grid md:grid-cols-2 md:gap-4">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm leading-5 font-medium text-indigo-600 truncate">{game.map}</div>
|
|
||||||
<div className="mt-2 flex items-center text-sm leading-5 text-gray-500">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">Played: {game.datestamp.split(/[T]/)[0]}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="hidden md:block">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm leading-5 text-gray-900">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex items-center">
|
|
||||||
<span className="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-indigo-100 text-indigo-800">{game.gametype}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<svg className="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
|
||||||
<path fillRule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clipRule="evenodd"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</InertiaLink>
|
|
||||||
</li>;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default function Games(props) {
|
|
||||||
return (
|
|
||||||
<Layout title={props.pageTitle}>
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-md">
|
|
||||||
<ul>
|
|
||||||
{ props.games.map((game, index) => GameRow(game, index)) }
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import Layout from '@/Shared/Layout'
|
|
||||||
|
|
||||||
|
|
||||||
export default function Index(props) {
|
|
||||||
return (
|
|
||||||
<Layout title={props.pageTitle}>
|
|
||||||
<div className="border-4 border-dashed border-gray-300 rounded-lg h-96">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { InertiaLink } from '@inertiajs/inertia-react'
|
|
||||||
import Layout from '@/Shared/Layout'
|
|
||||||
|
|
||||||
const returnTotalSumGames = (player) => {
|
|
||||||
let sum = Number(player.total_games_ctfgame) +
|
|
||||||
Number(player.total_games_dmgame) +
|
|
||||||
Number(player.total_games_lakrabbitgame) +
|
|
||||||
Number(player.total_games_sctfgame);
|
|
||||||
return sum
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const PlayerRow = (player, index) => {
|
|
||||||
|
|
||||||
let totalGames = returnTotalSumGames(player);
|
|
||||||
|
|
||||||
// only display players that have games associated
|
|
||||||
if (totalGames === 0){return}
|
|
||||||
|
|
||||||
return <li key={index}>
|
|
||||||
<InertiaLink href={`/player/${player.player_guid}`} className="block hover:bg-gray-50 focus:outline-none focus:bg-gray-50 transition duration-150 ease-in-out">
|
|
||||||
<div className="flex items-center px-4 py-4 sm:px-6">
|
|
||||||
<div className="min-w-0 flex-1 flex items-center">
|
|
||||||
<div className="min-w-0 flex-1 md:grid md:grid-cols-2 md:gap-4">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm leading-5 font-medium text-indigo-600 truncate">{player.player_name}</div>
|
|
||||||
<div className="mt-2 flex items-center text-sm leading-5 text-gray-500">
|
|
||||||
<span className="truncate">Last Active: {player.updated_at.split(/[T]/)[0]}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="hidden md:block">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm leading-5 text-gray-900">
|
|
||||||
Total Games Played
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex items-center">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{ totalGames }</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<svg className="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
|
||||||
<path fillRule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clipRule="evenodd"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</InertiaLink>
|
|
||||||
</li>;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default function Players(props) {
|
|
||||||
return (
|
|
||||||
<Layout title={props.pageTitle}>
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-md">
|
|
||||||
<ul>
|
|
||||||
{ props.players.map((player, index) => PlayerRow(player, index)) }
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { InertiaLink } from '@inertiajs/inertia-react';
|
|
||||||
import Layout from '@/Shared/Layout';
|
|
||||||
import GameTypesPlayedCols from '@/Components/GameTypesPlayedCols';
|
|
||||||
|
|
||||||
import { Radar, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis } from 'recharts';
|
|
||||||
|
|
||||||
const returnWeaponTotals = (statTotals) => {
|
|
||||||
let totals = [
|
|
||||||
{ weapon: 'Chaingun', val: statTotals['cgKillsTG'] },
|
|
||||||
{ weapon: 'Disc', val: statTotals['discKillsTG'] },
|
|
||||||
{ weapon: 'Grenade Launcher', val: statTotals['grenadeKillsTG'] },
|
|
||||||
{ weapon: 'Shocklance', val: statTotals['shockKillsTG'] },
|
|
||||||
{ weapon: 'Laser Rifle', val: statTotals['laserKillsTG'] },
|
|
||||||
{ weapon: 'Blaster', val: statTotals['blasterKillsTG'] },
|
|
||||||
{ weapon: 'Plasma Rifle', val: statTotals['plasmaKillsTG'] },
|
|
||||||
{ weapon: 'Mortar Launcher', val: statTotals['mortarKillsTG'] },
|
|
||||||
{ weapon: 'Missile Launcher', val: statTotals['missileKillsTG'] },
|
|
||||||
{ weapon: 'Hand Grenade', val: statTotals['hGrenadeKillsTG'] },
|
|
||||||
{ weapon: 'Mine', val: statTotals['mineKillsTG'] },
|
|
||||||
{ weapon: 'Satchel', val: statTotals['satchelKillsTG'] }
|
|
||||||
];
|
|
||||||
|
|
||||||
// dont return if the val is 0
|
|
||||||
return totals.filter(function(el) {
|
|
||||||
return el.val > 0;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const GameCard = (player, index) => {
|
|
||||||
// only display card if player has score
|
|
||||||
// if (Number(player.stats.score) <= 0){return}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={index} className="bg-white shadow overflow-hidden sm:rounded-lg mb-5">
|
|
||||||
<div className="px-4 py-5 border-b border-gray-200 sm:px-6">
|
|
||||||
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-no-wrap">
|
|
||||||
<div className="ml-4 mt-4">
|
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
|
||||||
<InertiaLink
|
|
||||||
href={`/game/${player.game_id}`}
|
|
||||||
className="text-indigo-600 hover:text-indigo-500 transition duration-150 ease-in-out"
|
|
||||||
>
|
|
||||||
{player.stats.map}
|
|
||||||
</InertiaLink>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
|
||||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">
|
|
||||||
{player.stats.dateStamp}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="ml-4 mt-4 flex-shrink-0">
|
|
||||||
<span className="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-indigo-100 text-indigo-800">
|
|
||||||
{player.gametype}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Total Score</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">{player.stats.scoreTG}</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Kills / Assists</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.killsTG} / {player.stats.assistTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">MAs</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">{player.stats.totalMATG}</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Flag Grabs / Caps</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.flagGrabsTG} / {player.stats.flagCapsTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Flag Defends / Carrier Kills / Returns</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
{player.stats.flagDefendsTG} / {player.stats.carrierKillsTG} / {player.stats.flagReturnsTG}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Player(props) {
|
|
||||||
return (
|
|
||||||
<Layout title={props.pageTitle}>
|
|
||||||
<div className="md:grid md:grid-cols-4 md:gap-6">
|
|
||||||
<div className="md:col-span-1">
|
|
||||||
<div className="px-4 sm:px-0">
|
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900">Aggregate</h3>
|
|
||||||
<p className="mt-1 text-sm leading-5 text-gray-500">Stat Totals</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-5 md:mt-0 md:col-span-3">
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
|
|
||||||
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<div className="text-sm leading-5 font-medium text-gray-500">Games Played</div>
|
|
||||||
<div className="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
|
||||||
<GameTypesPlayedCols
|
|
||||||
ctf={props.playerData.player.total_games_ctfgame}
|
|
||||||
dm={props.playerData.player.total_games_dmgame}
|
|
||||||
lak={props.playerData.player.total_games_lakrabbitgame}
|
|
||||||
spawnctf={props.playerData.player.total_games_sctfgame}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 px-4 py-5">
|
|
||||||
<dt className="text-sm leading-5 font-medium text-gray-500">Weapon Usage</dt>
|
|
||||||
<dd className="mt-1 text-sm leading-5 text-gray-900 flex items-center justify-center">
|
|
||||||
<RadarChart
|
|
||||||
cx={300}
|
|
||||||
cy={250}
|
|
||||||
outerRadius={150}
|
|
||||||
width={600}
|
|
||||||
height={500}
|
|
||||||
data={
|
|
||||||
returnWeaponTotals(props.playerData.totals).length ? (
|
|
||||||
returnWeaponTotals(props.playerData.totals)
|
|
||||||
) : (
|
|
||||||
[ { weapon: 'No Data', val: 1 } ]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="text-xs"
|
|
||||||
>
|
|
||||||
<PolarGrid />
|
|
||||||
<PolarAngleAxis dataKey="weapon" />
|
|
||||||
<PolarRadiusAxis />
|
|
||||||
<Radar
|
|
||||||
name={props.playerData.player.player_name}
|
|
||||||
dataKey="val"
|
|
||||||
stroke="#8884d8"
|
|
||||||
fill="#8884d8"
|
|
||||||
fillOpacity={0.6}
|
|
||||||
/>
|
|
||||||
</RadarChart>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="md:grid md:grid-cols-4 md:gap-6 mt-10">
|
|
||||||
<div className="md:col-span-1">
|
|
||||||
<div className="px-4 sm:px-0">
|
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900">Game History</h3>
|
|
||||||
<p className="mt-1 text-sm leading-5 text-gray-500">
|
|
||||||
Stats for past {props.playerData.stats.length} games
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-5 md:mt-0 md:col-span-3">
|
|
||||||
{props.playerData.stats.map((player, index) => GameCard(player, index))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/*
|
|
||||||
|
|
||||||
<div className="bg-white shadow overflow-hidden sm:rounded-md">
|
|
||||||
<div className="py-10 px-10"><code> {JSON.stringify(props.playerData.stats)}</code></div>
|
|
||||||
</div> */}
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import React, { useEffect } from 'react'
|
|
||||||
|
|
||||||
import TopNav from '../Components/TopNav';
|
|
||||||
import FrameHeading from '../Components/FrameHeading'
|
|
||||||
|
|
||||||
export default function Layout({ title, gametype, children }) {
|
|
||||||
useEffect(() => {
|
|
||||||
document.title = title + ' - Tribes 2 Stats';
|
|
||||||
}, [title])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TopNav />
|
|
||||||
<FrameHeading heading={title} gametype={gametype} />
|
|
||||||
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
|
||||||
<div className="px-4 py-4 sm:px-0">
|
|
||||||
{ children }
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { InertiaApp } from '@inertiajs/inertia-react'
|
|
||||||
import React from 'react'
|
|
||||||
import { render } from 'react-dom'
|
|
||||||
|
|
||||||
const app = document.getElementById('app')
|
|
||||||
|
|
||||||
render(
|
|
||||||
<InertiaApp
|
|
||||||
initialPage={JSON.parse(app.dataset.page)}
|
|
||||||
resolveComponent={name => import(`@/Pages/${name}`).then(module => module.default)}
|
|
||||||
/>,
|
|
||||||
app
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is required to enable HMR
|
|
||||||
if (module.hot) {
|
|
||||||
module.hot.accept();
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
@import "tailwindcss/base";
|
|
||||||
|
|
||||||
@import "tailwindcss/components";
|
|
||||||
|
|
||||||
@import "tailwindcss/utilities";
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<title>Tribes 2 Stats</title>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
|
||||||
@if(node_env().env === "production")
|
|
||||||
{{ style(versioncss('main')) }}
|
|
||||||
@else
|
|
||||||
{{ style('dist/css/main') }}
|
|
||||||
@endif
|
|
||||||
</head>
|
|
||||||
<body class="antialiased font-sans bg-gray-200">
|
|
||||||
|
|
||||||
<div id="popup" class="relative bg-indigo-600">
|
|
||||||
<div class="max-w-screen-xl mx-auto py-3 px-3 sm:px-6 lg:px-8">
|
|
||||||
<div class="pr-16 sm:text-center sm:px-16">
|
|
||||||
<p class="font-medium text-white">
|
|
||||||
Hey! This is a preview. Things aren't quite finished yet. Stay tuned!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="absolute inset-y-0 right-0 pt-1 pr-1 flex items-start sm:pt-1 sm:pr-2 sm:items-start">
|
|
||||||
<button type="button" class="flex p-2 rounded-md hover:bg-indigo-500 focus:outline-none focus:bg-indigo-500 transition ease-in-out duration-150" onclick="closePopUp()">
|
|
||||||
<svg class="h-6 w-6 text-white" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{{{ startTag }}}
|
|
||||||
|
|
||||||
{{-- {{ edgeVar }} --}}
|
|
||||||
@if(node_env().env === "production" || node_env().hmr === "false")
|
|
||||||
{{ script(versionjs('app')) }}
|
|
||||||
@else
|
|
||||||
{{ script('http://localhost:8081/dist/js/app.js') }}
|
|
||||||
@endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function closePopUp(){
|
|
||||||
document.getElementById("popup").remove();
|
|
||||||
};
|
|
||||||
|
|
||||||
if(top != self){
|
|
||||||
setInterval(() => {
|
|
||||||
parent.postMessage(document.getElementById('app').clientHeight, '*');
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Http server
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This file bootstrap Adonisjs to start the HTTP server. You are free to
|
|
||||||
| customize the process of booting the http server.
|
|
||||||
|
|
|
||||||
| """ Loading ace commands """
|
|
||||||
| At times you may want to load ace commands when starting the HTTP server.
|
|
||||||
| Same can be done by chaining `loadCommands()` method after
|
|
||||||
|
|
|
||||||
| """ Preloading files """
|
|
||||||
| Also you can preload files by calling `preLoad('path/to/file')` method.
|
|
||||||
| Make sure to pass relative path from the project root.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { Ignitor } = require('@adonisjs/ignitor')
|
|
||||||
|
|
||||||
new Ignitor(require('@adonisjs/fold'))
|
|
||||||
.appRoot(__dirname)
|
|
||||||
.fireHttpServer()
|
|
||||||
.catch(console.error)
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Providers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Providers are building blocks for your Adonis app. Anytime you install
|
|
||||||
| a new Adonis specific package, chances are you will register the
|
|
||||||
| provider here.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const providers = [
|
|
||||||
'@adonisjs/framework/providers/AppProvider',
|
|
||||||
'@adonisjs/framework/providers/ViewProvider',
|
|
||||||
'@adonisjs/lucid/providers/LucidProvider',
|
|
||||||
'@adonisjs/cors/providers/CorsProvider',
|
|
||||||
'inertia-adonis/providers/InertiaProvider'
|
|
||||||
]
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Ace Providers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Ace providers are required only when running ace commands. For example
|
|
||||||
| Providers for migrations, tests etc.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const aceProviders = [
|
|
||||||
]
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Aliases
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Aliases are short unique names for IoC container bindings. You are free
|
|
||||||
| to create your own aliases.
|
|
||||||
|
|
|
||||||
| For example:
|
|
||||||
| { Route: 'Adonis/Src/Route' }
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const aliases = {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Commands
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here you store ace commands for your package
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const commands = []
|
|
||||||
|
|
||||||
module.exports = { providers, aceProviders, aliases, commands }
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
const { hooks } = require('@adonisjs/ignitor')
|
|
||||||
const { version } = require('../package.json')
|
|
||||||
const Helpers = use('Helpers')
|
|
||||||
|
|
||||||
const mixManifest = require(Helpers.publicPath('mix-manifest.json'))
|
|
||||||
|
|
||||||
hooks.after.providersBooted(async () => {
|
|
||||||
const View = use('View')
|
|
||||||
|
|
||||||
View.global('node_env', () => {
|
|
||||||
return { "env": process.env.NODE_ENV, "hmr": process.env.WEBPACK_HMR }
|
|
||||||
})
|
|
||||||
|
|
||||||
View.global('versionjs', (filename) => {
|
|
||||||
filename = `/dist/js/${filename}.js`
|
|
||||||
if (!mixManifest.hasOwnProperty(filename)) {
|
|
||||||
throw new Error('Could not find asset for versioning' + filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mixManifest[filename]
|
|
||||||
})
|
|
||||||
|
|
||||||
View.global('versioncss', (filename) => {
|
|
||||||
filename = `/dist/css/${filename}.css`
|
|
||||||
if (!mixManifest.hasOwnProperty(filename)) {
|
|
||||||
throw new Error('Could not find asset for versioning' + filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mixManifest[filename]
|
|
||||||
})
|
|
||||||
|
|
||||||
const Inertia = use('Adonis/Addons/Inertia')
|
|
||||||
|
|
||||||
// these vars get pushed to the inertia frontend
|
|
||||||
Inertia.setVersion(version)
|
|
||||||
Inertia.share('app.name', process.env.APP_NAME)
|
|
||||||
})
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/** @type {import('@adonisjs/framework/src/Server')} */
|
|
||||||
const Server = use('Server')
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Global Middleware
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Global middleware are executed on each http request only when the routes
|
|
||||||
| match.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const globalMiddleware = [
|
|
||||||
'Adonis/Middleware/Inertia'
|
|
||||||
]
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Named Middleware
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Named middleware is key/value object to conditionally add middleware on
|
|
||||||
| specific routes or group of routes.
|
|
||||||
|
|
|
||||||
| // define
|
|
||||||
| {
|
|
||||||
| auth: 'Adonis/Middleware/Auth'
|
|
||||||
| }
|
|
||||||
|
|
|
||||||
| // use
|
|
||||||
| Route.get().middleware('auth')
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const namedMiddleware = {}
|
|
||||||
|
|
||||||
Server
|
|
||||||
.registerGlobal(globalMiddleware)
|
|
||||||
.registerNamed(namedMiddleware)
|
|
||||||
.use([
|
|
||||||
'Adonis/Middleware/Static',
|
|
||||||
'Adonis/Middleware/Cors'
|
|
||||||
])
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Routes
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Http routes are entry points to your web application. You can create
|
|
||||||
| routes for different URLs and bind Controller actions to them.
|
|
||||||
|
|
|
||||||
| A complete guide on routing is available here.
|
|
||||||
| http://adonisjs.com/docs/4.0/routing
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @type {typeof import('@adonisjs/framework/src/Route/Manager')} */
|
|
||||||
const Route = use('Route')
|
|
||||||
|
|
||||||
// [ Routes ]
|
|
||||||
//Route.get('/', 'IndexController.index').as('home')
|
|
||||||
//temp set games as home
|
|
||||||
Route.get('/', 'GameController.index').as('home')
|
|
||||||
|
|
||||||
// [ player ]
|
|
||||||
Route.get('/players', 'PlayerController.index')
|
|
||||||
Route.get('/player/:player_guid', 'PlayerController.player')
|
|
||||||
|
|
||||||
// [ game ]
|
|
||||||
Route.get('/games', 'GameController.index')
|
|
||||||
Route.get('/game/:game_id', 'GameController.game')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Container Healthcheck route
|
|
||||||
Route.get('/healthz', () => {
|
|
||||||
return { status: "healthy" };
|
|
||||||
})
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
const defaultTheme = require('tailwindcss/defaultTheme')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
fontFamily: {
|
|
||||||
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
variants: {},
|
|
||||||
plugins: [
|
|
||||||
require('@tailwindcss/ui'),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
const mix = require('laravel-mix');
|
|
||||||
|
|
||||||
//require('laravel-mix-tailwind');
|
|
||||||
require('laravel-mix-purgecss');
|
|
||||||
const tailwindcss = require('tailwindcss');
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Mix Asset Management
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Mix provides a clean, fluent API for defining some Webpack build steps
|
|
||||||
| for your Laravel application. By default, we are compiling the Sass
|
|
||||||
| file for the application as well as bundling up all the JS files.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
// transpiling, babelling, minifying and creating the public/js/main.js out of our assets
|
|
||||||
mix.setPublicPath('public')
|
|
||||||
.react('resources/js/app.js', 'public/dist/js')
|
|
||||||
// .sass('resources/scss/main.scss', 'public/dist/css')
|
|
||||||
.postCss('resources/scss/main.css', 'public/dist/css')
|
|
||||||
// .tailwind('./tailwind.config.js');
|
|
||||||
|
|
||||||
mix.webpackConfig({
|
|
||||||
output: {
|
|
||||||
chunkFilename: './dist/js/[name].[contenthash].js'
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.(css)/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: {
|
|
||||||
ident: 'postcss',
|
|
||||||
plugins: [
|
|
||||||
tailwindcss('./tailwind.config.js'),
|
|
||||||
require('autoprefixer'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
"@": path.resolve(
|
|
||||||
__dirname,
|
|
||||||
"resources/js"
|
|
||||||
),
|
|
||||||
"@sass": path.resolve(
|
|
||||||
__dirname,
|
|
||||||
"resources/scss"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
devServer: {
|
|
||||||
proxy: {
|
|
||||||
host: '0.0.0.0', // host machine ip
|
|
||||||
port: 8080,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mix.options({
|
|
||||||
hmrOptions: {
|
|
||||||
host: '0.0.0.0', // site's host name
|
|
||||||
port: 8081
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
if (mix.inProduction()) {
|
|
||||||
mix.purgeCss({
|
|
||||||
content: [
|
|
||||||
'./resources/**/*.edge',
|
|
||||||
'./resources/**/*.js',
|
|
||||||
'./resources/**/*.jsx',
|
|
||||||
'./resources/**/*.ts',
|
|
||||||
'./resources/**/*.tsx'
|
|
||||||
],
|
|
||||||
// default in mix
|
|
||||||
//defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
|
|
||||||
// default tailwind
|
|
||||||
defaultExtractor: content => content.match(/[\w-/.:]+(?<!:)/g) || [],
|
|
||||||
whitelistPatterns: [/-active$/, /-enter$/, /-leave-to$/]
|
|
||||||
});
|
|
||||||
|
|
||||||
mix.version();
|
|
||||||
}else{
|
|
||||||
// use SourceMaps on dev
|
|
||||||
mix.sourceMaps();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Full mix API
|
|
||||||
// mix.js(src, output);
|
|
||||||
// mix.react(src, output); <-- Identical to mix.js(), but registers React Babel compilation.
|
|
||||||
// mix.preact(src, output); <-- Identical to mix.js(), but registers Preact compilation.
|
|
||||||
// mix.coffee(src, output); <-- Identical to mix.js(), but registers CoffeeScript compilation.
|
|
||||||
// mix.ts(src, output); <-- TypeScript support. Requires tsconfig.json to exist in the same folder as webpack.mix.js
|
|
||||||
// mix.extract(vendorLibs);
|
|
||||||
// mix.sass(src, output);
|
|
||||||
// mix.standaloneSass('src', output); <-- Faster, but isolated from Webpack.
|
|
||||||
// mix.fastSass('src', output); <-- Alias for mix.standaloneSass().
|
|
||||||
// mix.less(src, output);
|
|
||||||
// mix.stylus(src, output);
|
|
||||||
// mix.postCss(src, output, [require('postcss-some-plugin')()]);
|
|
||||||
// mix.browserSync('my-site.test');
|
|
||||||
// mix.combine(files, destination);
|
|
||||||
// mix.babel(files, destination); <-- Identical to mix.combine(), but also includes Babel compilation.
|
|
||||||
// mix.copy(from, to);
|
|
||||||
// mix.copyDirectory(fromDir, toDir);
|
|
||||||
// mix.minify(file);
|
|
||||||
// mix.sourceMaps(); // Enable sourcemaps
|
|
||||||
// mix.version(); // Enable versioning.
|
|
||||||
// mix.disableNotifications();
|
|
||||||
// mix.setPublicPath('path/to/public');
|
|
||||||
// mix.setResourceRoot('prefix/for/resource/locators');
|
|
||||||
// mix.autoload({}); <-- Will be passed to Webpack's ProvidePlugin.
|
|
||||||
// mix.webpackConfig({}); <-- Override webpack.config.js, without editing the file directly.
|
|
||||||
// mix.babelConfig({}); <-- Merge extra Babel configuration (plugins, etc.) with Mix's default.
|
|
||||||
// mix.then(function () {}) <-- Will be triggered each time Webpack finishes building.
|
|
||||||
// mix.extend(name, handler) <-- Extend Mix's API with your own components.
|
|
||||||
// mix.options({
|
|
||||||
// extractVueStyles: false, // Extract .vue component styling to file, rather than inline.
|
|
||||||
// globalVueStyles: file, // Variables file to be imported in every component.
|
|
||||||
// processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched.
|
|
||||||
// purifyCss: false, // Remove unused CSS selectors.
|
|
||||||
// uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
|
|
||||||
// postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md
|
|
||||||
// });
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
.git
|
|
||||||
node_modules
|
|
||||||
public/dist
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
# [ Stage 1 ] - install node modules
|
|
||||||
FROM node:12.2-alpine as builder
|
|
||||||
RUN apk update
|
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
|
|
||||||
COPY ./app/webapp/package.json /build/package.json
|
|
||||||
COPY ./app/webapp/package-lock.json /build/package-lock.json
|
|
||||||
|
|
||||||
RUN npm install
|
|
||||||
RUN npm i --global @adonisjs/cli
|
|
||||||
|
|
||||||
RUN npx adonis key:generate --echo
|
|
||||||
|
|
||||||
# ============================
|
|
||||||
# ============================
|
|
||||||
|
|
||||||
# [ Stage 2 ]
|
|
||||||
FROM node:12.2-alpine
|
|
||||||
LABEL maintainer="Anthony Mineo <anthonymineo@gmail.com>"
|
|
||||||
|
|
||||||
RUN apk update && apk add --no-cache bash curl
|
|
||||||
|
|
||||||
# Default envs as prod
|
|
||||||
ENV ENV_SILENT=true \
|
|
||||||
HOST=0.0.0.0 \
|
|
||||||
PORT=8080 \
|
|
||||||
HASH_DRIVER=bcrypt \
|
|
||||||
NODE_ENV=production \
|
|
||||||
WEBPACK_HMR=false \
|
|
||||||
CACHE_VIEWS=true \
|
|
||||||
APP_NAME=AdonisJs
|
|
||||||
ENV APP_URL=http://${HOST}:${PORT}
|
|
||||||
|
|
||||||
#ENV APP_KEY=you-need-to-generate-this
|
|
||||||
# secrets path _FILE prefix or ENV K=V
|
|
||||||
|
|
||||||
|
|
||||||
# Setup pm2 as our node process manager
|
|
||||||
# https://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/
|
|
||||||
RUN npm install pm2 -g
|
|
||||||
|
|
||||||
# Set node modules outside our app to keep it clean
|
|
||||||
COPY --from=builder /build/node_modules/ /opt/node_modules/
|
|
||||||
ENV PATH /opt/node_modules/.bin:$PATH
|
|
||||||
|
|
||||||
|
|
||||||
# Start script and config
|
|
||||||
COPY ./build/webapp/entrypoint.sh /entrypoint.sh
|
|
||||||
|
|
||||||
# Our App
|
|
||||||
WORKDIR /app
|
|
||||||
COPY ./app/webapp /app
|
|
||||||
|
|
||||||
RUN ln -nsf /opt/node_modules /app
|
|
||||||
|
|
||||||
|
|
||||||
# Bake prod assets into image
|
|
||||||
RUN rm -rf /app/public/dist && npm run webpack-server
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=20s --timeout=30s --start-period=5s --retries=5 \
|
|
||||||
CMD curl -f http://localhost:8080/healthz || exit 1
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo "Node ENV: $NODE_ENV"
|
|
||||||
|
|
||||||
file_env() {
|
|
||||||
local var="$1"
|
|
||||||
local fileVar="${var}_FILE"
|
|
||||||
local def="${2:-}"
|
|
||||||
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
|
||||||
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
local val="$def"
|
|
||||||
if [ "${!var:-}" ]; then
|
|
||||||
val="${!var}"
|
|
||||||
elif [ "${!fileVar:-}" ]; then
|
|
||||||
val="$(< "${!fileVar}")"
|
|
||||||
fi
|
|
||||||
export "$var"="$val"
|
|
||||||
unset "$fileVar"
|
|
||||||
}
|
|
||||||
|
|
||||||
file_env 'APP_KEY'
|
|
||||||
|
|
||||||
|
|
||||||
# Exit if APP_KEY is missing, this key is important!
|
|
||||||
if [ -z "$APP_KEY" ]
|
|
||||||
then
|
|
||||||
echo >&2 "[ERROR] No ENV for APP_KEY or APP_KEY_FILE found!"
|
|
||||||
echo >&2 "Run the ./generate-adonis-app-key.sh script or provide one at runtime"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [[ "$NODE_ENV" == "development" ]]; then
|
|
||||||
echo "Prepping container for dev environment"
|
|
||||||
echo "Setting a symlink for ./node_modules -> /opt/node_modules"
|
|
||||||
ln -nsf /opt/node_modules /app
|
|
||||||
|
|
||||||
echo "Cleaning dist assets..."
|
|
||||||
rm -rf /app/public/dist
|
|
||||||
npm run webpack-server
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Generate a dist assets if they don't exist -- (If they were deleted on the volume mount)
|
|
||||||
[ ! -d "/app/public/dist" ] && npm run webpack-server
|
|
||||||
|
|
||||||
|
|
||||||
if [[ "$NODE_ENV" == "production" ]]; then
|
|
||||||
pm2-runtime start /app/ecosystem._PROD_.config.js
|
|
||||||
elif [[ "$WEBPACK_HMR" == "true" ]]; then
|
|
||||||
pm2-runtime start /app/ecosystem._DEV_HOT_.config.js
|
|
||||||
else
|
|
||||||
pm2-runtime start /app/ecosystem._DEV_.config.js
|
|
||||||
fi
|
|
||||||
|
|
@ -21,19 +21,6 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./app/t2-stat-parser:/app
|
- ./app/t2-stat-parser:/app
|
||||||
|
|
||||||
# web:
|
|
||||||
# environment:
|
|
||||||
# DB_USER: "dev"
|
|
||||||
# DB_PASSWORD: "dev"
|
|
||||||
# CACHE_VIEWS: "false"
|
|
||||||
# NODE_ENV: "development" # auto-reloads app on save, dev builds
|
|
||||||
# WEBPACK_HMR: "true" # default is false -- this is useful for when you're focused on Frontend Dev
|
|
||||||
# ports:
|
|
||||||
# - "8080:8080" # adonis http port
|
|
||||||
# - "8081:8081" # webpack-dev-server port
|
|
||||||
# volumes:
|
|
||||||
# - ./app/webapp:/app
|
|
||||||
|
|
||||||
api:
|
api:
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: "development" # auto-reloads app on save
|
NODE_ENV: "development" # auto-reloads app on save
|
||||||
|
|
|
||||||
|
|
@ -57,35 +57,6 @@ services:
|
||||||
- internal
|
- internal
|
||||||
- external
|
- external
|
||||||
|
|
||||||
# web:
|
|
||||||
# image: "amineo/t2-stats-web:v0.1.0-rc6"
|
|
||||||
# build:
|
|
||||||
# context: .
|
|
||||||
# dockerfile: ./build/webapp/Dockerfile
|
|
||||||
# environment:
|
|
||||||
# NODE_ENV: "production" # set as default in image
|
|
||||||
# CACHE_VIEWS: "true" # set as default in image
|
|
||||||
# APP_NAME: "Web" # set as default in image
|
|
||||||
# # APP_KEY: "You-need-to-generate-this (npx adonis key:generate --echo)"
|
|
||||||
# APP_KEY_FILE: /run/secrets/adonis.appkey
|
|
||||||
# DB_HOST: "db"
|
|
||||||
# DB_PORT: 5432
|
|
||||||
# DB_USER: ""
|
|
||||||
# DB_PASSWORD: ""
|
|
||||||
# DB_DATABASE: t2_stats
|
|
||||||
# secrets:
|
|
||||||
# - adonis.appkey
|
|
||||||
# ports:
|
|
||||||
# - "8080:8080"
|
|
||||||
# networks:
|
|
||||||
# - internal
|
|
||||||
# - external
|
|
||||||
# deploy:
|
|
||||||
# # labels:
|
|
||||||
# # - traefik.enable=false
|
|
||||||
# mode: replicated
|
|
||||||
# replicas: 1
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
psqldata:
|
psqldata:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
echo "Checking to see if @adonisjs/cli has been installed..."
|
|
||||||
|
|
||||||
package='@adonisjs/cli'
|
|
||||||
if [ `npm list -g | grep -c $package` -eq 0 ]; then
|
|
||||||
while true; do
|
|
||||||
echo "-----------------------------------------------"
|
|
||||||
echo " Adonis CLI not installed"
|
|
||||||
echo "-----------------------------------------------"
|
|
||||||
read -p "Would you like to install this now? [Y/N] " yn
|
|
||||||
case $yn in
|
|
||||||
[Yy]* ) npm i --global @adonisjs/cli; break;;
|
|
||||||
[Nn]* ) break;;
|
|
||||||
* ) echo "Please answer yes or no.";;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "Looks good!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
echo "Generating key..."
|
|
||||||
APPKEY=$(npx adonis key:generate --echo)
|
|
||||||
|
|
||||||
echo -n "${APPKEY/APP_KEY=}" > ./docker-secrets/adonis.appkey.v1
|
|
||||||
|
|
||||||
echo "Done! Don't share it with anyone!"
|
|
||||||
echo "The key is located here: ./docker-secrets/adonis.appkey.v1"
|
|
||||||
Loading…
Reference in a new issue