Add generated API code and use for task creation

Co-authored-by: Deniz Kusefoglu <deniz@influxdata.com>
pull/10616/head
Brandon Farmer 2018-11-19 14:03:28 -08:00
parent 0bdb3414ae
commit b4aa8ff1d6
17 changed files with 15474 additions and 126 deletions

6
.gitignore vendored
View File

@ -22,3 +22,9 @@ ui/node_modules
ui/yarn-error.log ui/yarn-error.log
ui/build ui/build
ui/.cache ui/.cache
ui/src/api/.gitignore
ui/src/api/.openapi-generator-ignore
ui/src/api/.openapi-generator/VERSION
ui/src/api/git_push.sh

View File

@ -149,6 +149,10 @@ chronogiraffe: subdirs generate $(CMDS)
run: chronogiraffe run: chronogiraffe
./bin/$(GOOS)/influxd --developer-mode=true ./bin/$(GOOS)/influxd --developer-mode=true
generate-typescript-client:
cat http/cur_swagger.yml | yq read -j - > openapi.json
openapi-generator generate -g typescript-axios -o ui/src/api -i openapi.json
rm openapi.json
# .PHONY targets represent actions that do not create an actual file. # .PHONY targets represent actions that do not create an actual file.
.PHONY: all subdirs $(SUBDIRS) ui run fmt checkfmt tidy checktidy test test-go test-js test-go-race bench clean node_modules vet nightly chronogiraffe .PHONY: all subdirs $(SUBDIRS) ui run fmt checkfmt tidy checktidy test test-go test-js test-go-race bench clean node_modules vet nightly chronogiraffe

View File

@ -3,7 +3,7 @@ info:
title: Influx API Service title: Influx API Service
version: 0.1.0 version: 0.1.0
servers: servers:
- url: /api/v2 - url: "http://localhost:9999/api/v2"
paths: paths:
/signin: /signin:
post: post:
@ -1490,8 +1490,6 @@ paths:
responses: responses:
'200': '200':
description: Abstract syntax tree of flux query. description: Abstract syntax tree of flux query.
content:
application/json: #TODO(goller): document the AST JSON schema
default: default:
description: Any response other than 200 is an internal server error description: Any response other than 200 is an internal server error
content: content:
@ -3452,24 +3450,23 @@ components:
annotations: annotations:
description: https://www.w3.org/TR/2015/REC-tabular-data-model-20151217/#columns description: https://www.w3.org/TR/2015/REC-tabular-data-model-20151217/#columns
type: array type: array
default: []
items: items:
type: string type: string
enum: enum:
- group - "group"
- datatype - "datatype"
- default - "default"
uniqueItems: true uniqueItems: true
commentPrefix: commentPrefix:
description: character prefixed to comment strings description: character prefixed to comment strings
type: string type: string
default: \# default: "#"
maxLength: 1 maxLength: 1
minLength: 0 minLength: 0
dateTimeFormat: dateTimeFormat:
description: format of timestamps description: format of timestamps
type: string type: string
default: RFC3339 default: "RFC3339"
enum: enum:
- RFC3339 - RFC3339
- RFC3339Nano - RFC3339Nano
@ -3764,7 +3761,7 @@ components:
id: id:
readOnly: true readOnly: true
type: string type: string
organization: organizationId:
description: The ID of the organization that owns this Task. description: The ID of the organization that owns this Task.
type: string type: string
name: name:
@ -3976,75 +3973,6 @@ components:
type: integer type: integer
format: int32 format: int32
required: [code, message, maxLength] required: [code, message, maxLength]
InfluxQLResults:
properties:
error:
description: error during processing of the message
type: string
results:
type: array
description: result for each query
items:
type: object
properties:
error:
type: string
description: error during processing of the message
partial:
type: boolean
description: If a max row limit has been placed in the configuration file and the number of returned values is larger, this will be set to true and values truncated.
statement_id:
type: integer
description: statement's position in the query.
series:
description: The collection of data in InfluxDBs data structure that share a measurement, tag set, and retention policy.
type: array
items:
type: object
description: values for a unique series
properties:
name:
description: The part of InfluxDBs structure that describes the data stored in the associated fields. Measurements are strings.
type: string
tags:
description: The key-value pairs in InfluxDBs data structure that records metadata.
type: object
columns:
description: list of columns describing the content of a single value array
type: array
items:
type: string
values:
description: array of arrays of the values return from the query
type: array
items:
type: array
description: single row of results in the order of the columns field.
items:
oneOf:
- type: string
- type: number
- type: integer
partial:
type: boolean
messages:
type: array
description: represents a user-facing message to be included with the result.
items:
type: object
properties:
level:
type: string
text:
type: string
InfluxqlQueryError:
properties:
error:
description: message describing why the query was rejected
readOnly: true
type: string
required:
- error
Field: Field:
type: object type: object
properties: properties:
@ -4782,14 +4710,6 @@ components:
type: array type: array
items: items:
type: string type: string
TelegrafPluginInputNginx:
type: object
properties:
urls:
type: array
items:
type: string
format: uri
TelegrafPluginInputProcstat: TelegrafPluginInputProcstat:
type: object type: object
properties: properties:

View File

@ -215,11 +215,7 @@ func (h *TaskHandler) handlePostTask(w http.ResponseWriter, r *http.Request) {
} }
if !req.Task.Owner.ID.Valid() { if !req.Task.Owner.ID.Valid() {
if err != nil { req.Task.Owner.ID = auth.GetUserID()
EncodeError(ctx, kerrors.Wrap(err, "invalid token", kerrors.InvalidData), w)
return
}
req.Task.Owner.ID = auth.Identifier()
} }
if err := h.TaskService.CreateTask(ctx, req.Task); err != nil { if err := h.TaskService.CreateTask(ctx, req.Task); err != nil {

15291
ui/src/api/api.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
// tslint:disable
/**
* Influx API Service
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* OpenAPI spec version: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface ConfigurationParameters {
apiKey?: string | ((name: string) => string);
username?: string;
password?: string;
accessToken?: string | ((name: string, scopes?: string[]) => string);
basePath?: string;
baseOptions?: any;
}
export class Configuration {
/**
* parameter for apiKey security
* @param name security name
* @memberof Configuration
*/
apiKey?: string | ((name: string) => string);
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
username?: string;
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
password?: string;
/**
* parameter for oauth2 security
* @param name security name
* @param scopes oauth2 scope
* @memberof Configuration
*/
accessToken?: string | ((name: string, scopes?: string[]) => string);
/**
* override base path
*
* @type {string}
* @memberof Configuration
*/
basePath?: string;
/**
* base options for axios calls
*
* @type {any}
* @memberof Configuration
*/
baseOptions?: any;
constructor(param: ConfigurationParameters = {}) {
this.apiKey = param.apiKey;
this.username = param.username;
this.password = param.password;
this.accessToken = param.accessToken;
this.basePath = param.basePath;
}
}

1
ui/src/api/custom.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'url';

16
ui/src/api/index.ts Normal file
View File

@ -0,0 +1,16 @@
// tslint:disable
/**
* Influx API Service
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* OpenAPI spec version: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export * from "./api";
export * from "./configuration";

View File

@ -1,7 +1,7 @@
import {AppState} from 'src/types/v2' import {AppState} from 'src/types/v2'
import {push} from 'react-router-redux' import {push} from 'react-router-redux'
import {Task} from 'src/types/v2/tasks' import {Task as TaskAPI, Organization} from 'src/api'
import { import {
submitNewTask, submitNewTask,
updateTaskFlux, updateTaskFlux,
@ -19,6 +19,7 @@ import {
taskNotFound, taskNotFound,
taskUpdateFailed, taskUpdateFailed,
} from 'src/shared/copy/v2/notifications' } from 'src/shared/copy/v2/notifications'
import {getDeep} from 'src/utils/wrappers'
import {taskOptionsToFluxScript} from 'src/utils/taskOptionsToFluxScript' import {taskOptionsToFluxScript} from 'src/utils/taskOptionsToFluxScript'
@ -37,7 +38,19 @@ export type Action =
| SetScheduleUnit | SetScheduleUnit
type GetStateFunc = () => AppState type GetStateFunc = () => AppState
interface Task extends TaskAPI {
organization: Organization
}
export enum ActionTypes {
SetNewScript = 'SET_NEW_SCRIPT',
SetTasks = 'SET_TASKS',
SetSearchTerm = 'SET_TASKS_SEARCH_TERM',
SetCurrentScript = 'SET_CURRENT_SCRIPT',
SetCurrentTask = 'SET_CURRENT_TASK',
SetShowInactive = 'SET_TASKS_SHOW_INACTIVE',
SetDropdownOrgID = 'SET_DROPDOWN_ORG_ID',
}
export interface ClearTaskOptions { export interface ClearTaskOptions {
type: 'CLEAR_TASK_OPTIONS' type: 'CLEAR_TASK_OPTIONS'
} }
@ -221,9 +234,11 @@ export const populateTasks = () => async (
const tasks = await getUserTasks(url, user) const tasks = await getUserTasks(url, user)
const mappedTasks = tasks.map(task => { const mappedTasks = tasks.map(task => {
const org = orgs.find(org => org.id === task.organizationId)
return { return {
...task, ...task,
organization: orgs.find(org => org.id === task.organizationId), organization: org,
} }
}) })
@ -240,12 +255,15 @@ export const selectTaskByID = (id: string) => async (
): Promise<void> => { ): Promise<void> => {
try { try {
const { const {
orgs,
links: {tasks: url}, links: {tasks: url},
} = getState() } = getState()
const org = orgs.find(org => org.id === task.organizationId)
const task = await getTask(url, id) const task = await getTask(url, id)
return dispatch(setCurrentTask(task)) return dispatch(setCurrentTask({...task, organization: org}))
} catch (e) { } catch (e) {
console.error(e) console.error(e)
dispatch(goToTasks()) dispatch(goToTasks())
@ -290,15 +308,12 @@ export const saveNewScript = () => async (
try { try {
const { const {
orgs, orgs,
links: {tasks: url, me: meUrl},
tasks: {newScript: script, taskOptions}, tasks: {newScript: script, taskOptions},
} = await getState() } = await getState()
const fluxTaskOptions = taskOptionsToFluxScript(taskOptions) const fluxTaskOptions = taskOptionsToFluxScript(taskOptions)
const scriptWithOptions = `${fluxTaskOptions}\n${script}` const scriptWithOptions = `${fluxTaskOptions}\n${script}`
const user = await getMe(meUrl)
let org = orgs.find(org => { let org = orgs.find(org => {
return org.id === taskOptions.orgID return org.id === taskOptions.orgID
}) })
@ -307,7 +322,7 @@ export const saveNewScript = () => async (
org = orgs[0] org = orgs[0]
} }
await submitNewTask(url, user, org, scriptWithOptions) await submitNewTask(getDeep<string>(org, 'id', ''), scriptWithOptions)
dispatch(setNewScript('')) dispatch(setNewScript(''))
dispatch(clearTaskOptions()) dispatch(clearTaskOptions())

View File

@ -1,20 +1,21 @@
import AJAX from 'src/utils/ajax' import AJAX from 'src/utils/ajax'
import {Task} from 'src/types/v2/tasks'
import {Task, TasksApi} from 'src/api'
const getBasePath = () => {
const host = window.location.hostname
const port = window.location.port
const protocol = window.location.protocol
return `${protocol}//${host}:${port}/api/v2`
}
export const submitNewTask = async ( export const submitNewTask = async (
url, organizationId: string,
owner,
org,
flux: string flux: string
): Promise<Task> => { ): Promise<Task> => {
const request = { const api = new TasksApi({basePath: getBasePath()})
flux, const {data} = await api.tasksPost({organizationId, flux})
organizationId: org.id,
status: 'active',
owner,
}
const {data} = await AJAX({url, data: request, method: 'POST'})
return data return data
} }

View File

@ -15,7 +15,7 @@ import TaskScheduleFormField from 'src/tasks/components/TaskScheduleFormField'
import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript' import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
import {Organization} from 'src/types/v2' import {Organization} from 'src/api'
import {Alignment, Direction} from 'src/clockface/types' import {Alignment, Direction} from 'src/clockface/types'
interface Props { interface Props {

View File

@ -15,9 +15,13 @@ import {
// Utils // Utils
import {downloadTextFile} from 'src/shared/utils/download' import {downloadTextFile} from 'src/shared/utils/download'
import {Task as TaskAPI, User, Organization} from 'src/api'
// Types interface Task extends TaskAPI {
import {Task, TaskStatus} from 'src/types/v2/tasks' organization: Organization
owner?: User
delay?: string
}
interface Props { interface Props {
task: Task task: Task
@ -91,7 +95,7 @@ class TaskRow extends PureComponent<Props & WithRouterProps> {
private get isTaskActive(): boolean { private get isTaskActive(): boolean {
const {task} = this.props const {task} = this.props
if (task.status === TaskStatus.Active) { if (task.status === TaskAPI.StatusEnum.Active) {
return true return true
} }
return false return false
@ -99,10 +103,10 @@ class TaskRow extends PureComponent<Props & WithRouterProps> {
private changeToggle = () => { private changeToggle = () => {
const {task, onActivate} = this.props const {task, onActivate} = this.props
if (task.status === TaskStatus.Active) { if (task.status === TaskAPI.StatusEnum.Active) {
task.status = TaskStatus.Inactive task.status = TaskAPI.StatusEnum.Inactive
} else { } else {
task.status = TaskStatus.Active task.status = TaskAPI.StatusEnum.Active
} }
onActivate(task) onActivate(task)
} }

View File

@ -6,8 +6,13 @@ import {IndexList} from 'src/clockface'
import TaskRow from 'src/tasks/components/TaskRow' import TaskRow from 'src/tasks/components/TaskRow'
// Types // Types
import {Task} from 'src/types/v2/tasks'
import EmptyTasksList from 'src/tasks/components/EmptyTasksList' import EmptyTasksList from 'src/tasks/components/EmptyTasksList'
import {Task as TaskAPI, User, Organization} from 'src/api'
interface Task extends TaskAPI {
organization: Organization
owner?: User
}
interface Props { interface Props {
tasks: Task[] tasks: Task[]

View File

@ -6,7 +6,7 @@ import _ from 'lodash'
import {Dropdown} from 'src/clockface' import {Dropdown} from 'src/clockface'
// Types // Types
import {Organization} from 'src/types/v2' import {Organization} from 'src/api'
interface Props { interface Props {
orgs: Organization[] orgs: Organization[]

View File

@ -5,8 +5,14 @@ import {connect} from 'react-redux'
import TaskForm from 'src/tasks/components/TaskForm' import TaskForm from 'src/tasks/components/TaskForm'
import TaskHeader from 'src/tasks/components/TaskHeader' import TaskHeader from 'src/tasks/components/TaskHeader'
import {Task} from 'src/types/v2/tasks'
import {Page} from 'src/pageLayout' import {Page} from 'src/pageLayout'
import {Task as TaskAPI, User, Organization} from 'src/api'
interface Task extends TaskAPI {
organization: Organization
owner?: User
delay?: string
}
import {Links} from 'src/types/v2/links' import {Links} from 'src/types/v2/links'
import {State as TasksState} from 'src/tasks/reducers/v2' import {State as TasksState} from 'src/tasks/reducers/v2'
@ -19,7 +25,6 @@ import {
setScheduleUnit, setScheduleUnit,
} from 'src/tasks/actions/v2' } from 'src/tasks/actions/v2'
import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript' import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
import {Organization} from 'src/types/v2'
interface PassedInProps { interface PassedInProps {
router: InjectedRouter router: InjectedRouter

View File

@ -24,8 +24,13 @@ import {
import {allOrganizationsID} from 'src/tasks/constants' import {allOrganizationsID} from 'src/tasks/constants'
// Types // Types
import {Task, TaskStatus} from 'src/types/v2/tasks' import {Task as TaskAPI, User, Organization} from 'src/api'
import {Organization} from 'src/types/v2'
interface Task extends TaskAPI {
organization: Organization
owner?: User
delay?: string
}
interface PassedInProps { interface PassedInProps {
router: InjectedRouter router: InjectedRouter
@ -119,7 +124,7 @@ class TasksPage extends PureComponent<Props> {
.includes(searchTerm.toLowerCase()) .includes(searchTerm.toLowerCase())
let activeFilter = true let activeFilter = true
if (!showInactive) { if (!showInactive) {
activeFilter = t.status === TaskStatus.Active activeFilter = t.status === TaskAPI.StatusEnum.Active
} }
let orgIDFilter = true let orgIDFilter = true
if (dropdownOrgID && dropdownOrgID !== allOrganizationsID) { if (dropdownOrgID && dropdownOrgID !== allOrganizationsID) {

View File

@ -1,7 +1,12 @@
import {Action} from 'src/tasks/actions/v2' import {Action} from 'src/tasks/actions/v2'
import {Task} from 'src/types/v2/tasks'
import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript' import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
import {Task as TaskAPI, User, Organization} from 'src/api'
interface Task extends TaskAPI {
organization: Organization
owner?: User
delay?: string
}
export interface State { export interface State {
newScript: string newScript: string
currentScript: string currentScript: string