-
Notifications
You must be signed in to change notification settings - Fork 0
CustomDB
Every team has different data they want to collect, and to account for that, the database model can easily be changed to support each team's needs.
Meerkat is designed to be a simple markup language that easily lets people without programming knowledge specify what information they want. The Meerkat file is then generated into the necessary code. Unfortunetly, it will not be available until the 1.0 release of Scouter
r1Hatch,number
r2Hatch,number
r3Hatch,number
r1Cargo,number
r2Cargo,number
r3Cargo,number
hab1,boolean
hab2,boolean
hab3,boolean
cCargo,number
cHatch,number
foul,number
techFoul,number
Since Meerkat is currently not developed yet, teams will need to make slight modification to the code in order to customize their stored information. Luckily, the changes are similar to what was shown for the example Meerkat file.
The files that need to be modified can be found in the app's resource directory. On Windows, this will be: C:\Users\{Username}\AppData\Local\Programs\scouter\resources
. On macOS, it can be found under TODO: Test on a mac and find it's location
In the server directory, navigate to server/src/models/matchModel.ts
and open the file. There should be a variable called matchSchema that looks similar to this:
const matchSchema = new Schema({
matchNumber: {
type: Number,
required: [true, "A match must have a number!"]
},
team: {
type: ObjectId,
ref: "Team"
},
csHatch: {
type: Number
},
// Lots of other pre-defined information...
habOne: {
type: Boolean
}
});
This object defines what statistics are held in the database. Each statistic you want to keep track of needs to be added in here.
NOTE: The matchNumber and team property ARE REQUIRED in order for Scouter to work. Do not modify these. Everything else that is pre-defined can be removed.
Statistics can be added using the following format:
nameOfStatistic: {
type: TypeOfTheStatistic
}
The type property must be one of the following: Number, String, Boolean (this is case sensitive). In order to decide which one to use, follow this simple flowchart:
- Is the statistic a number such as 2, -5, 3.14, or 100000?
- Yes: Use Number
- No: Can the statistic be described as yes/no, true/false, or 1/0? (such as did the robot reach hab level 1 or climb at the end)
- Yes: Use Boolean
- No: Use String (which is essentially a sequence of text, such as a sentence)
Here are a few examples:
If I want to store how many balls a robot placed on the 2nd level of a rocket ship, I could call it r2Ball and it's type would be Number.
r2Ball: {
type: Number
}
If I want to store wheather or not a robot climbed the 2nd level of a platform, I could call it l2Platform and it's type would be Boolean. (this is a yes/no type statistic)
l2Platform: {
type: Boolean
}
If I wanted to store any comments or observations the scout had while observing their robot, I could call it observations and it's type would be String.
observations: {
type: String
}
Putting this all together, the final result would look like:
const matchSchema = new Schema({
matchNumber: {
type: Number,
required: [true, "A match must have a number!"]
},
team: {
type: ObjectId,
ref: "Team"
},
r2Ball: {
type: Number
},
l2Platform: {
type: Boolean
},
observations: {
type: String
}
});
Notice how each property for a statistic has a comma at the end (},
) so long as it's not the last one in the list.
NOTE: You can use a site such as this to make sure your code has valid syntax
In the client directory, navigate to client/src/reducers/data.ts
and open the file. There should be a interface called IMatch that looks similar to this:
export interface IMatch {
csHatch: number;
csCargo: number;
r1Hatch: number;
r2Hatch: number;
r3Hatch: number;
r1Cargo: number;
r2Cargo: number;
r3Cargo: number;
l1Hab: boolean;
l2Hab: boolean;
l3Hab: boolean;
}
The IMatch interface needs to contain all of the statistics that were defined in the previous file. However, unlike the previous file where each statistic was assigned to an object with a type property, these statistics are directly assigned the type.
NOTE: Unlike the previous types, which had the first letter in uppercase, these are all lowercase.
Using the example from the previous file, IMatch should then be:
export interface IMatch {
r2Ball: number;
l2Platform: boolean;
observations: string;
}
NOTE: Notice that matchNumber and team shouldn't be defined here.
In the client directory, navigate to client/src/helper/matchDataCompiler.ts
and open the file. There should be a function called generateMatchData that looks similar to this:
function generateMatchData(defaultNum: number): IMatch {
return {
csHatch: defaultNum,
csCargo: defaultNum,
r1Hatch: defaultNum,
r2Hatch: defaultNum,
r3Hatch: defaultNum,
r1Cargo: defaultNum,
r2Cargo: defaultNum,
r3Cargo: defaultNum
};
}
This function is used to initalize the numerical statistics to a default number (to aid in calculating things like the minimum, maximum, average, etc).
To make the necessary changes, take all of your statistis that are of type number and assign them to the parameter defaultNum. Using the on-going example, this would look like:
function generateMatchData(defaultNum: number): IMatch {
return {
r2Ball: defaultNum
};
}
NOTE: While the previous examples had the statistics r2Ball, l2Platform, and observations, we only define r2Ball here since that is the only one of type number.
Finally, in the client directory, navigate to client/src/components/RouterComponents/DataInput/DataInputFormComponents/DataForm.tsx
and open the file. Inside of the DataForm class, there should be a method called render()
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form className="data__form" onSubmit={this.handleSubmit}>
<Form.Item label="Cargo Ship Hatches:">
{getFieldDecorator("csHatch", {})(<Input />)}
</Form.Item>
<Form.Item label="Cargo Ship Cargo:">
{getFieldDecorator("csCargo", {})(<Input />)}
</Form.Item>
<Form.Item label="Rocket L1 Hatches:">
{getFieldDecorator("r1Hatch", {})(<Input />)}
</Form.Item>
<Form.Item label="Rocket L2 Hatches:">
{getFieldDecorator("r2Hatch", {})(<Input />)}
</Form.Item>
<Form.Item label="Rocket L3 Hatches:">
{getFieldDecorator("r3Hatch", {})(<Input />)}
</Form.Item>
<Form.Item label="Rocket L1 Cargo:">
{getFieldDecorator("r1Cargo", {})(<Input />)}
</Form.Item>
<Form.Item label="Rocket L2 Cargo:">
{getFieldDecorator("r2Cargo", {})(<Input />)}
</Form.Item>
<Form.Item label="Rocket L3 Cargo:">
{getFieldDecorator("r3Cargo", {})(<Input />)}
</Form.Item>
<Form.Item>
<Button className="" type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
}
This file creates the form that the scouts enter the data into. Every render function, at the bare minimum, should contain:
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form className="data__form" onSubmit={this.handleSubmit}>
<Form.Item>
<Button className="" type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
)
}
For each statistic that was defined in the matchModel, the following should be added inside the
component:<Form.Item label="The label for the input:">
{getFieldDecorator("statisticName", {})(<Input />)}
</Form.Item>
Using the on-going example, the resulting form would look like:
TODO: boolean fields
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form className="data__form" onSubmit={this.handleSubmit}>
<Form.Item label="Rocket Level 2 Balls:">
{getFieldDecorator("r2Ball", {})(<Input />)}
</Form.Item>
<Form.Item label="Level 2 Platform:">
{getFieldDecorator("l2Platform", {})(<Input />)}
</Form.Item>
<Form.Item label="Observations / Comments">
{getFieldDecorator("observations", {})(<Input />)}
</Form.Item>
<Form.Item>
<Button className="" type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
)
}
Quick Navigation