Merge pull request #6 from AAVikings/master
New client and server version
This commit is contained in:
20 files changed
+132
-127
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@superalgos/operations-client",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"description": "Superalgos Operations client-side web app",
|
||||
"main": "src/index.js",
|
||||
"dependencies": {
|
||||
|
||||
@@ -24,7 +24,7 @@ export const clone = gql`
|
||||
combinedProfitsB
|
||||
assetA
|
||||
assetB
|
||||
kind
|
||||
botType
|
||||
teamName
|
||||
botName
|
||||
botAvatar
|
||||
|
||||
@@ -435,7 +435,8 @@ class AddClone extends Component {
|
||||
botId: this.state.selectedBot.id,
|
||||
mode: this.state.mode,
|
||||
resumeExecution: this.state.resumeExecution,
|
||||
runAsTeam: this.state.runAsTeam
|
||||
runAsTeam: this.state.runAsTeam,
|
||||
botType: this.getBotTypeFromKind(this.state.selectedBot.kind)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,6 +458,15 @@ class AddClone extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
getBotTypeFromKind(kind){
|
||||
if(kind === 'TRADER')
|
||||
return 'Trading'
|
||||
else if(kind === 'INDICATOR')
|
||||
return 'Indicator'
|
||||
else if(kind === 'EXTRACTOR')
|
||||
return 'Extraction'
|
||||
}
|
||||
|
||||
handleNewCloneConfirmationOpen = () => {
|
||||
this.setState({ isNewCloneConfirmationOpen: true })
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ class ListClones extends Component {
|
||||
<div className={classes.details}>
|
||||
<div className={classes.column4}>
|
||||
<Typography className={classes.cloneInfoBold}>Last Execution:</Typography>
|
||||
{ (clone.kind === 'TRADER' && isDefined(clone.assetA) ) &&
|
||||
{ (clone.botType === 'Trading' && isDefined(clone.assetA) ) &&
|
||||
<React.Fragment>
|
||||
<Typography className={classes.cloneInfoBold}>Buy Average:</Typography>
|
||||
<Typography className={classes.cloneInfoBold}>Sell Average:</Typography>
|
||||
@@ -100,7 +100,7 @@ class ListClones extends Component {
|
||||
</div>
|
||||
<div className={classes.column4}>
|
||||
<Typography className={classes.cloneInfoNormal}>{isDefined(clone.summaryDate) ? toLocalTime(clone.summaryDate): 'waiting update...'}</Typography>
|
||||
{ ((clone.kind === 'INDICATOR' || clone.kind === 'EXTRACTOR') && isDefined(clone.assetA) ) &&
|
||||
{ ((clone.botType === 'Indicator' || clone.botType === 'Extraction') && isDefined(clone.assetA) ) &&
|
||||
<React.Fragment>
|
||||
<Typography className={classes.cloneInfoNormal}>{clone.buyAverage}</Typography>
|
||||
<Typography className={classes.cloneInfoNormal}>{clone.sellAverage}</Typography>
|
||||
@@ -187,7 +187,7 @@ class ListClones extends Component {
|
||||
<DialogTitle id="logs-dialog-title">
|
||||
Last clone logs
|
||||
</DialogTitle>
|
||||
<DialogContent className={classes.logsDialog}>
|
||||
<DialogContent>
|
||||
<Typography className={classes.typography} variant='subtitle1' align='justify'>
|
||||
Here you can check the clone output directly from the virtual machine.
|
||||
The last 20 lines are displayed, but you can check the Logs Module for more details.
|
||||
|
||||
@@ -33,9 +33,11 @@ const styles = theme => ({
|
||||
},
|
||||
textArea: {
|
||||
width:'1750px',
|
||||
marginLeft: theme.spacing.unit,
|
||||
marginRight: theme.spacing.unit,
|
||||
margin: theme.spacing.unit,
|
||||
whiteSpace: 'pre',
|
||||
width:'98%',
|
||||
overflowY:'hidden',
|
||||
overflowX:'hidden'
|
||||
},
|
||||
heading: {
|
||||
fontSize: theme.typography.pxToRem(18),
|
||||
@@ -50,13 +52,10 @@ const styles = theme => ({
|
||||
borderLeft: `2px solid ${theme.palette.divider}`,
|
||||
padding: `0px ${theme.spacing.unit * 2}px`,
|
||||
},
|
||||
logsDialog:{
|
||||
overflowY:'hidden',
|
||||
overflowX:'hidden'
|
||||
},
|
||||
logsWrapper:{
|
||||
width:'1750px',
|
||||
overflowY:'auto',
|
||||
overflowX:'auto'
|
||||
overflowX:'hidden'
|
||||
},
|
||||
details:{
|
||||
display:'flex'
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"containers": [
|
||||
{
|
||||
"name": "aadev",
|
||||
"image": "benme/aadev:v3.3",
|
||||
"image": "benme/aadev:v3.4",
|
||||
"command": ["node", "Run.js"],
|
||||
"env": [
|
||||
]
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import 'dotenv/config'
|
||||
|
||||
const env = []
|
||||
|
||||
env.push({
|
||||
"name": "PLATFORM_ENVIRONMENT",
|
||||
"value": process.env.PLATFORM_ENVIRONMENT
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "GATEWAY_ENDPOINT",
|
||||
"value": process.env.GATEWAY_ENDPOINT
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "STORAGE_BASE_URL",
|
||||
"value": process.env.STORAGE_BASE_URL
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "STORAGE_CONNECTION_STRING",
|
||||
"value": process.env.STORAGE_CONNECTION_STRING
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "AUTH_URL",
|
||||
"value": process.env.AUTH_URL
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "AUTH_CLIENT_ID",
|
||||
"value": process.env.AUTH_CLIENT_ID
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "AUTH_CLIENT_SECRET",
|
||||
"value": process.env.AUTH_CLIENT_SECRET
|
||||
})
|
||||
|
||||
env.push({
|
||||
"name": "AUTH_AUDIENCE",
|
||||
"value": process.env.AUTH_AUDIENCE
|
||||
})
|
||||
|
||||
export default env
|
||||
@@ -8,8 +8,8 @@ export function isDefined (d) {
|
||||
return d !== null && typeof d !== 'undefined'
|
||||
}
|
||||
|
||||
export function getJobNameFromClone (teamSlug, botSlug, mode) {
|
||||
return teamSlug + '-' + botSlug + '-' + mode.toLowerCase()
|
||||
export function getJobNameFromClone (clone) {
|
||||
return clone.teamSlug + '-' + clone.botSlug + '-' + clone.mode.toLowerCase()
|
||||
}
|
||||
|
||||
export function getSelectedBot(botsByUser, selectedBotId){
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export const TRADER = 'Trading'
|
||||
export const INDICATOR = 'Indicator'
|
||||
export const EXTRACTION = 'Extraction'
|
||||
|
||||
export const BotTypesEnum = [
|
||||
TRADER,
|
||||
INDICATOR,
|
||||
EXTRACTION
|
||||
]
|
||||
|
||||
export default BotTypesEnum
|
||||
@@ -1,9 +1,11 @@
|
||||
export const LIVE = 'Live'
|
||||
export const BACKTEST = 'Backtest'
|
||||
export const COMPETITION = 'Competition'
|
||||
export const ALL_MONTHS = 'All Months'
|
||||
export const ONE_MONTH = 'One Month'
|
||||
export const NO_TIME = 'No Time'
|
||||
export const ALL_MONTHS = 'allMonths'
|
||||
export const ONE_MONTH = 'oneMonth'
|
||||
export const NO_TIME = 'noTime'
|
||||
export const FIXED_INTERVAL = 'fixedInterval'
|
||||
|
||||
|
||||
export const CloneModeEnum = [
|
||||
LIVE,
|
||||
@@ -11,7 +13,8 @@ export const CloneModeEnum = [
|
||||
COMPETITION,
|
||||
ALL_MONTHS,
|
||||
ONE_MONTH,
|
||||
NO_TIME
|
||||
NO_TIME,
|
||||
FIXED_INTERVAL
|
||||
]
|
||||
|
||||
export default CloneModeEnum
|
||||
@@ -5,7 +5,6 @@ export class AuthentificationError extends Error {
|
||||
message = 'Autentification not found, you have to be authentificated to perform this action'
|
||||
constructor(){
|
||||
super()
|
||||
logger.error(this.stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +13,6 @@ export class DatabaseError extends Error {
|
||||
message = 'Ressource not found : ' + this.message
|
||||
constructor(message){
|
||||
super(message)
|
||||
logger.error(this.stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +21,6 @@ export class WrongArgumentsError extends Error {
|
||||
message = 'Wrong arguments : ' + this.message
|
||||
constructor(message){
|
||||
super(message)
|
||||
logger.error(this.stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +29,6 @@ export class ServiceUnavailableError extends Error {
|
||||
message = 'At least one service is unresponding ' + this.message
|
||||
constructor(message){
|
||||
super(message)
|
||||
logger.error(this.stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +48,3 @@ export class KubernateError extends Error {
|
||||
logger.error(this.stack)
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomError extends Error {
|
||||
code = 500
|
||||
message = this.message
|
||||
constructor(message){
|
||||
super(message)
|
||||
logger.error(this.stack)
|
||||
this.stack = ''
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,66 @@
|
||||
import logger from '../config/logger'
|
||||
import { toPlatformDatetime, getJobNameFromClone, isDefined } from '../config/utils'
|
||||
import envConfig from '../config/envConfig'
|
||||
import { toPlatformDatetime, isDefined } from '../config/utils'
|
||||
import { KubernateError } from '../errors'
|
||||
import { Client, config } from 'kubernetes-client'
|
||||
// Get base Deployment config
|
||||
import deploymentManifest from '../config/clone-deployment.json'
|
||||
import { BACKTEST} from '../enums/CloneMode';
|
||||
|
||||
const createClone = async (clone, teamSlug, botSlug) => {
|
||||
const createClone = async (clone) => {
|
||||
try {
|
||||
let cloneName = getJobNameFromClone(teamSlug, botSlug, clone.mode)
|
||||
logger.info("createClone %s", cloneName)
|
||||
logger.info("createClone %j", clone)
|
||||
const client = new Client({config: config.fromKubeconfig(), version: '1.9'})
|
||||
|
||||
// Make changes to base deployment config
|
||||
deploymentManifest.metadata.name = cloneName
|
||||
deploymentManifest.metadata.name = clone.cloneName
|
||||
|
||||
logger.debug("createClone Environment and Auth Configuration.")
|
||||
let env = envConfig
|
||||
let env = []
|
||||
env.push({
|
||||
"name": "PLATFORM_ENVIRONMENT",
|
||||
"value": process.env.PLATFORM_ENVIRONMENT
|
||||
})
|
||||
env.push({
|
||||
"name": "GATEWAY_ENDPOINT",
|
||||
"value": process.env.GATEWAY_ENDPOINT
|
||||
})
|
||||
env.push({
|
||||
"name": "STORAGE_BASE_URL",
|
||||
"value": process.env.STORAGE_BASE_URL
|
||||
})
|
||||
env.push({
|
||||
"name": "STORAGE_CONNECTION_STRING",
|
||||
"value": process.env.STORAGE_CONNECTION_STRING
|
||||
})
|
||||
env.push({
|
||||
"name": "AUTH_URL",
|
||||
"value": process.env.AUTH_URL
|
||||
})
|
||||
env.push({
|
||||
"name": "AUTH_CLIENT_ID",
|
||||
"value": process.env.AUTH_CLIENT_ID
|
||||
})
|
||||
env.push({
|
||||
"name": "AUTH_CLIENT_SECRET",
|
||||
"value": process.env.AUTH_CLIENT_SECRET
|
||||
})
|
||||
env.push({
|
||||
"name": "AUTH_AUDIENCE",
|
||||
"value": process.env.AUTH_AUDIENCE
|
||||
})
|
||||
|
||||
logger.debug("createClone General Financial Being Configuration.")
|
||||
env.push({
|
||||
"name": "DEV_TEAM",
|
||||
"value": clone.teamId
|
||||
"value": clone.teamSlug
|
||||
})
|
||||
env.push({
|
||||
"name": "BOT",
|
||||
"value": clone.botId
|
||||
"value": clone.botSlug
|
||||
})
|
||||
env.push({
|
||||
"name": "TYPE",
|
||||
"value": clone.kind
|
||||
})
|
||||
env.push({
|
||||
"name": "PROCESS",
|
||||
"value": clone.processName
|
||||
"value": clone.botType
|
||||
})
|
||||
env.push({
|
||||
"name": "CLONE_ID",
|
||||
@@ -54,7 +80,11 @@ const createClone = async (clone, teamSlug, botSlug) => {
|
||||
})
|
||||
|
||||
logger.debug("createClone Trading Configuration.")
|
||||
if(clone.kind === 'Trading'){
|
||||
if(clone.botType === 'Trading'){
|
||||
env.push({
|
||||
"name": "PROCESS",
|
||||
"value": 'Trading-Process'
|
||||
})
|
||||
env.push({
|
||||
"name": "RESUME_EXECUTION",
|
||||
"value": clone.resumeExecution.toString()
|
||||
@@ -74,7 +104,11 @@ const createClone = async (clone, teamSlug, botSlug) => {
|
||||
"value": clone.waitTime.toString()
|
||||
})
|
||||
}
|
||||
} else if(clone.kind === 'Indicator' || clone.kind === 'Extractor'){
|
||||
} else if(clone.botType === 'Indicator' || clone.botType === 'Extraction'){
|
||||
env.push({
|
||||
"name": "PROCESS",
|
||||
"value": clone.processName
|
||||
})
|
||||
env.push({
|
||||
"name": "MIN_YEAR",
|
||||
"value": isDefined(clone.startYear) ? clone.startYear.toString() : ''
|
||||
@@ -93,12 +127,13 @@ const createClone = async (clone, teamSlug, botSlug) => {
|
||||
})
|
||||
}
|
||||
|
||||
logger.debug("Configuration: %j.", env)
|
||||
deploymentManifest.spec.template.spec.containers[0].env = env
|
||||
|
||||
const create = await client.apis.batch.v1.namespaces('default').jobs.post(
|
||||
{ body: deploymentManifest })
|
||||
|
||||
logger.info("createClone %s on Kubernates success.", cloneName)
|
||||
logger.info("createClone %s on Kubernates success.", clone.cloneName)
|
||||
} catch (err) {
|
||||
throw new KubernateError(err)
|
||||
}
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
import logger from '../config/logger'
|
||||
import { KubernateError } from '../errors'
|
||||
import { Client, config } from 'kubernetes-client'
|
||||
import { getJobNameFromClone } from '../config/utils'
|
||||
|
||||
const removeClone = async (clone, teamSlug, botSlug) => {
|
||||
const removeClone = async (clone) => {
|
||||
try {
|
||||
let cloneName = getJobNameFromClone(teamSlug, botSlug, clone.mode)
|
||||
logger.info("removeClone %s", cloneName)
|
||||
logger.info("removeClone %s", clone.cloneName)
|
||||
const client = new Client({config: config.fromKubeconfig(), version: '1.9'})
|
||||
|
||||
let query = {
|
||||
"qs":{
|
||||
"labelSelector": "job-name="+cloneName
|
||||
"labelSelector": "job-name=" + clone.cloneName
|
||||
}
|
||||
}
|
||||
|
||||
const removed = await client.apis.batch.v1.namespaces('default').jobs(
|
||||
cloneName).delete()
|
||||
clone.cloneName).delete()
|
||||
|
||||
const pod = await client.api.v1.namespaces('default').pods.get(query)
|
||||
const podRemoved = await client.api.v1.namespaces('default')
|
||||
.pods(pod.body.items[0].metadata.name).delete()
|
||||
|
||||
logger.info("removeClone %s on kubernates succesful", cloneName)
|
||||
logger.info("removeClone %s on kubernates succesful", clone.cloneName)
|
||||
} catch (err) {
|
||||
throw new KubernateError(err)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import logger from '../../config/logger'
|
||||
import { getJobNameFromClone, getSelectedBot } from '../../config/utils'
|
||||
import teamAvatar from '../../graphQLCalls/teamAvatar'
|
||||
import logger from '../config/logger'
|
||||
import { getJobNameFromClone, getSelectedBot } from '../config/utils'
|
||||
import teamAvatar from '../graphQLCalls/teamAvatar'
|
||||
|
||||
// TODO Refactor this code once financial beings api is ready
|
||||
const cloneDetails = async(authorization, botsByUser, clone) => {
|
||||
logger.debug('Retrieving clone details.')
|
||||
// TODO Refactor this code once financial beings api is ready
|
||||
|
||||
let selectedBot = getSelectedBot(botsByUser.data.data.teams_FbByTeamMember, clone.botId)
|
||||
clone.cloneName = getJobNameFromClone(botsByUser.data.data.teams_FbByTeamMember.slug, selectedBot.slug, clone.mode)
|
||||
clone.kind = selectedBot.kind
|
||||
clone.teamId = botsByUser.data.data.teams_FbByTeamMember.id
|
||||
clone.botId = selectedBot.id
|
||||
clone.teamSlug = botsByUser.data.data.teams_FbByTeamMember.slug
|
||||
clone.botSlug = selectedBot.slug
|
||||
clone.cloneName = getJobNameFromClone(clone)
|
||||
clone.teamName = botsByUser.data.data.teams_FbByTeamMember.name
|
||||
clone.botName = selectedBot.name
|
||||
clone.botAvatar = selectedBot.avatar
|
||||
|
||||
let team = await teamAvatar(authorization, botsByUser.data.data.teams_FbByTeamMember.id)
|
||||
clone.teamAvatar = team.data.data.teams_TeamById.profile.avatar
|
||||
clone.userLoggedIn = botsByUser.data.data.teams_FbByTeamMember.members[0].member.alias //TODO change by context info if possible
|
||||
|
||||
logger.debug('Retrieving clone details complete.')
|
||||
return clone
|
||||
};
|
||||
@@ -2,13 +2,14 @@ import { CloneInputType } from '../types/input';
|
||||
import { CloneType } from '../types';
|
||||
import { Clone } from '../../models';
|
||||
import { CloneModeEnum } from '../../enums/CloneMode';
|
||||
import { BotTypesEnum } from '../../enums/BotTypes';
|
||||
import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember';
|
||||
import cloneDetails from '../cloneDetails'
|
||||
|
||||
import {
|
||||
AuthentificationError,
|
||||
WrongArgumentsError,
|
||||
OperationsError,
|
||||
CustomError
|
||||
OperationsError
|
||||
} from '../../errors'
|
||||
|
||||
import logger from '../../config/logger'
|
||||
@@ -30,6 +31,10 @@ const resolve = async(parent, { clone }, context) => {
|
||||
throw new WrongArgumentsError('The mode selected is not valid.')
|
||||
}
|
||||
|
||||
if(!Object.values(BotTypesEnum).includes(clone.botType)){
|
||||
throw new WrongArgumentsError('The bot type selected is not valid.')
|
||||
}
|
||||
|
||||
let existingClone = await Clone.find(
|
||||
{
|
||||
authId: context.userId,
|
||||
@@ -40,25 +45,23 @@ const resolve = async(parent, { clone }, context) => {
|
||||
|
||||
logger.debug('addClone -> Checking existing clone %j', existingClone)
|
||||
if(existingClone.length > 0){
|
||||
throw new CustomError('You can only have one active clone by mode. Remove the'
|
||||
throw new OperationsError('You can only have one active clone by mode. Remove the'
|
||||
+ ' existing clone of type: ' + clone.mode + ' and try again.')
|
||||
}
|
||||
|
||||
try{
|
||||
// Authorization is handled by the teams module
|
||||
let botsByUser = await teams_FbByTeamMember(context.authorization)
|
||||
clone = await cloneDetails(context.authorization, botsByUser, clone)
|
||||
let selectedBot = getSelectedBot(botsByUser.data.data.teams_FbByTeamMember, clone.botId)
|
||||
clone.teamId = botsByUser.data.data.teams_FbByTeamMember.id
|
||||
clone.botId = selectedBot.id
|
||||
clone.userLoggedIn = botsByUser.data.data.teams_FbByTeamMember.members[0].member.alias //TODO change by context info if possible
|
||||
clone.createDatetime = new Date().valueOf() / 1000|0
|
||||
clone.active = true
|
||||
|
||||
logger.debug('addClone -> Creating a new clone. %j', clone)
|
||||
logger.debug('addClone -> Creating a new clone.')
|
||||
let newClone = new Clone(clone)
|
||||
newClone.id = newClone._id
|
||||
newClone.authId = context.userId
|
||||
await createKubernetesClone(newClone, botsByUser.data.data.teams_FbByTeamMember.slug, selectedBot.slug )
|
||||
clone.id = newClone._id
|
||||
await createKubernetesClone(clone)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
newClone.save((err) => {
|
||||
|
||||
@@ -14,6 +14,7 @@ import logger from '../../config/logger'
|
||||
import removeKuberneteClone from '../../kubernetes/removeClone'
|
||||
import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember'
|
||||
import { isDefined, getSelectedBot } from '../../config/utils'
|
||||
import cloneDetails from '../cloneDetails'
|
||||
|
||||
const args = {
|
||||
id: { type: new GraphQLNonNull(GraphQLID) }
|
||||
@@ -33,15 +34,14 @@ const resolve = async (parent, { id }, context) => {
|
||||
})
|
||||
|
||||
if(!isDefined(clone)){
|
||||
throw new CustomError('You are not authorized to remove this clone.')
|
||||
throw new OperationsError('You are not authorized to remove this clone.')
|
||||
}
|
||||
|
||||
// Authorization is also handled by the teams module
|
||||
let botsByUser = await teams_FbByTeamMember(context.authorization)
|
||||
let selectedBot = getSelectedBot(botsByUser.data.data.teams_FbByTeamMember, clone.botId)
|
||||
clone = await cloneDetails(context.authorization, botsByUser, clone)
|
||||
|
||||
logger.debug('removeClone -> Removing Clone from Kubernates.')
|
||||
await removeKuberneteClone(clone, botsByUser.data.data.teams_FbByTeamMember.slug, selectedBot.slug)
|
||||
await removeKuberneteClone(clone)
|
||||
|
||||
const query = {
|
||||
_id: id,
|
||||
|
||||
@@ -12,7 +12,7 @@ import logger from '../../config/logger'
|
||||
import getKuberneteClonePodStatus from '../../kubernetes/getClonePodStatus'
|
||||
import getKuberneteClonePodLogs from '../../kubernetes/getClonePodLogs'
|
||||
import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember'
|
||||
import cloneDetails from './cloneDetails'
|
||||
import cloneDetails from '../cloneDetails'
|
||||
|
||||
const args = {}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import logger from '../../config/logger'
|
||||
import getCloneStatus from '../../kubernetes/getClonePodStatus'
|
||||
import getCloneLogs from '../../kubernetes/getClonePodLogs'
|
||||
import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember'
|
||||
import cloneDetails from './cloneDetails'
|
||||
import cloneDetails from '../cloneDetails'
|
||||
|
||||
const args = {}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ const CloneType = new GraphQLObjectType({
|
||||
combinedProfitsB: {type: GraphQLFloat},
|
||||
assetA: {type: GraphQLString},
|
||||
assetB: {type: GraphQLString},
|
||||
kind: {type: GraphQLString},
|
||||
botType: {type: GraphQLString},
|
||||
teamName: {type: GraphQLString},
|
||||
botName: {type: GraphQLString},
|
||||
botAvatar: {type: GraphQLString},
|
||||
|
||||
@@ -22,7 +22,7 @@ const Type = new GraphQLInputObjectType({
|
||||
month: { type: GraphQLInt },
|
||||
interval: { type: GraphQLInt },
|
||||
processName: { type: GraphQLString },
|
||||
kind: { type: GraphQLString }
|
||||
botType: { type: new GraphQLNonNull(GraphQLString) }
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user