refactor(ui): normalization of tasks (#16445)
* refactor: normalize tasks resource * fix: pull tasks off of response * refactor: use action to clear current task * refactor: stop getting all tasks in every thunkpull/16451/head
parent
625ab8999d
commit
62398d04b4
|
@ -304,12 +304,11 @@ export const checkBucketLimits = () => (dispatch, getState: GetState) => {
|
|||
export const checkTaskLimits = () => (dispatch, getState: GetState) => {
|
||||
try {
|
||||
const {
|
||||
tasks: {list},
|
||||
cloud: {limits},
|
||||
resources,
|
||||
} = getState()
|
||||
|
||||
const tasksMax = extractTaskMax(limits)
|
||||
const tasksCount = list.length
|
||||
const tasksCount = resources.tasks.allIDs.length
|
||||
|
||||
if (tasksCount >= tasksMax) {
|
||||
dispatch(setTaskLimitStatus(LimitStatus.EXCEEDED))
|
||||
|
|
|
@ -7,16 +7,15 @@ import {withRouter, WithRouterProps} from 'react-router'
|
|||
import TaskForm from 'src/tasks/components/TaskForm'
|
||||
|
||||
// Actions
|
||||
import {saveNewScript} from 'src/tasks/actions/thunks'
|
||||
import {
|
||||
saveNewScript,
|
||||
setTaskOption,
|
||||
clearTask,
|
||||
setNewScript,
|
||||
} from 'src/tasks/actions'
|
||||
} from 'src/tasks/actions/creators'
|
||||
import {refreshTimeMachineVariableValues} from 'src/timeMachine/actions/queries'
|
||||
|
||||
// Utils
|
||||
import {getActiveTimeMachine, getActiveQuery} from 'src/timeMachine/selectors'
|
||||
import {getTimeRangeVars} from 'src/variables/utils/getTimeRangeVars'
|
||||
import {getWindowVars} from 'src/variables/utils/getWindowVars'
|
||||
import {formatVarsOption} from 'src/variables/utils/formatVarsOption'
|
||||
|
@ -24,17 +23,20 @@ import {
|
|||
taskOptionsToFluxScript,
|
||||
addDestinationToFluxScript,
|
||||
} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {getVariableAssignments} from 'src/variables/selectors'
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
import {getActiveTimeMachine, getActiveQuery} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {AppState, TimeRange, VariableAssignment} from 'src/types'
|
||||
import {
|
||||
AppState,
|
||||
TimeRange,
|
||||
VariableAssignment,
|
||||
TaskSchedule,
|
||||
TaskOptions,
|
||||
TaskOptionKeys,
|
||||
} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {DashboardDraftQuery} from 'src/types/dashboards'
|
||||
import {getVariableAssignments} from 'src/variables/selectors'
|
||||
DashboardDraftQuery,
|
||||
} from 'src/types'
|
||||
|
||||
interface OwnProps {
|
||||
dismiss: () => void
|
||||
|
@ -163,10 +165,7 @@ class SaveAsTaskForm extends PureComponent<Props & WithRouterProps> {
|
|||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {
|
||||
tasks: {newScript, taskOptions},
|
||||
} = state
|
||||
|
||||
const {newScript, taskOptions} = state.resources.tasks
|
||||
const {timeRange} = getActiveTimeMachine(state)
|
||||
const activeQuery = getActiveQuery(state)
|
||||
const org = getOrg(state)
|
||||
|
|
|
@ -2,35 +2,50 @@
|
|||
import {schema} from 'normalizr'
|
||||
|
||||
// Types
|
||||
import {ResourceType, Telegraf} from 'src/types'
|
||||
import {ResourceType, Telegraf, Task, Label} from 'src/types'
|
||||
|
||||
// Utils
|
||||
import {addLabelDefaults} from 'src/labels/utils'
|
||||
|
||||
/* Authorizations */
|
||||
|
||||
// Defines the schema for the "auth" resource
|
||||
// Defines the schema for the "authorizations" resource
|
||||
export const auth = new schema.Entity(ResourceType.Authorizations)
|
||||
export const arrayOfAuths = [auth]
|
||||
|
||||
/* Buckets */
|
||||
|
||||
// Defines the schema for the "bucket" resource
|
||||
// Defines the schema for the "buckets" resource
|
||||
export const bucket = new schema.Entity(ResourceType.Buckets)
|
||||
export const arrayOfBuckets = [bucket]
|
||||
|
||||
/* Members */
|
||||
|
||||
// Defines the schema for the "member" resource
|
||||
// Defines the schema for the "members" resource
|
||||
export const member = new schema.Entity(ResourceType.Members)
|
||||
export const arrayOfMembers = [member]
|
||||
|
||||
/* Organizations */
|
||||
|
||||
// Defines the schema for the "member" resource
|
||||
// Defines the schema for the "organizations" resource
|
||||
export const org = new schema.Entity(ResourceType.Orgs)
|
||||
export const arrayOfOrgs = [org]
|
||||
|
||||
/* Tasks */
|
||||
// Defines the schema for the tasks resource
|
||||
export const task = new schema.Entity(
|
||||
ResourceType.Tasks,
|
||||
{},
|
||||
{
|
||||
processStrategy: (task: Task) => addLabels<Task>(task),
|
||||
}
|
||||
)
|
||||
|
||||
export const arrayOfTasks = [task]
|
||||
|
||||
/* Telegrafs */
|
||||
|
||||
// Defines the schema for the "member" resource
|
||||
// Defines the schema for the "telegrafs" resource
|
||||
export const telegraf = new schema.Entity(
|
||||
ResourceType.Telegrafs,
|
||||
{},
|
||||
|
@ -69,3 +84,10 @@ export const arrayOfTelegrafs = [telegraf]
|
|||
|
||||
export const scraper = new schema.Entity(ResourceType.Scrapers)
|
||||
export const arrayOfScrapers = [scraper]
|
||||
|
||||
export const addLabels = <R extends {labels?: Label[]}>(resource: R): R => {
|
||||
return {
|
||||
...resource,
|
||||
labels: (resource.labels || []).map(addLabelDefaults),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import {getPlugins} from 'src/dataLoaders/actions/telegrafEditor'
|
|||
import {getVariables} from 'src/variables/actions'
|
||||
import {getScrapers} from 'src/scrapers/actions/thunks'
|
||||
import {getDashboardsAsync} from 'src/dashboards/actions'
|
||||
import {getTasks} from 'src/tasks/actions'
|
||||
import {getTasks} from 'src/tasks/actions/thunks'
|
||||
import {getAuthorizations} from 'src/authorizations/actions/thunks'
|
||||
import {getTemplates} from 'src/templates/actions'
|
||||
import {getMembers} from 'src/members/actions/thunks'
|
||||
|
|
|
@ -11,6 +11,7 @@ export const getResourcesStatus = (
|
|||
case ResourceType.Members:
|
||||
case ResourceType.Buckets:
|
||||
case ResourceType.Telegrafs:
|
||||
case ResourceType.Tasks:
|
||||
case ResourceType.Scrapers:
|
||||
case ResourceType.Authorizations: {
|
||||
return state.resources[resource].status
|
||||
|
|
|
@ -71,12 +71,12 @@ export const rootReducer = combineReducers<ReducerState>({
|
|||
members: membersReducer,
|
||||
orgs: orgsReducer,
|
||||
scrapers: scrapersReducer,
|
||||
tokens: authsReducer,
|
||||
tasks: tasksReducer,
|
||||
telegrafs: telegrafsReducer,
|
||||
tokens: authsReducer,
|
||||
}),
|
||||
routing: routerReducer,
|
||||
rules: rulesReducer,
|
||||
tasks: tasksReducer,
|
||||
telegrafEditor: editorReducer,
|
||||
telegrafEditorActivePlugins: activePluginsReducer,
|
||||
telegrafEditorPlugins: pluginsReducer,
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
// Types
|
||||
import {
|
||||
Run,
|
||||
LogEvent,
|
||||
TaskOptionKeys,
|
||||
RemoteDataState,
|
||||
TaskEntities,
|
||||
} from 'src/types'
|
||||
import {NormalizedSchema} from 'normalizr'
|
||||
|
||||
export const SET_TASKS = 'SET_TASKS'
|
||||
export const EDIT_TASK = 'EDIT_TASK'
|
||||
export const SET_TASK_OPTION = 'SET_TASK_OPTION'
|
||||
export const SET_ALL_TASK_OPTIONS = 'SET_ALL_TASK_OPTIONS'
|
||||
export const CLEAR_TASK = 'CLEAR_TASK'
|
||||
export const CLEAR_CURRENT_TASK = 'CLEAR_CURRENT_TASK'
|
||||
export const SET_NEW_SCRIPT = 'SET_NEW_SCRIPT'
|
||||
export const SET_CURRENT_SCRIPT = 'SET_CURRENT_SCRIPT'
|
||||
export const SET_CURRENT_TASK = 'SET_CURRENT_TASK'
|
||||
export const SET_SEARCH_TERM = 'SET_SEARCH_TERM'
|
||||
export const SET_SHOW_INACTIVE = 'SET_SHOW_INACTIVE'
|
||||
export const SET_RUNS = 'SET_RUNS'
|
||||
export const SET_LOGS = 'SET_LOGS'
|
||||
export const REMOVE_TASK = 'REMOVE_TASK'
|
||||
export const ADD_TASK = 'ADD_TASK'
|
||||
|
||||
export type Action =
|
||||
| ReturnType<typeof setTasks>
|
||||
| ReturnType<typeof editTask>
|
||||
| ReturnType<typeof setTaskOption>
|
||||
| ReturnType<typeof setAllTaskOptions>
|
||||
| ReturnType<typeof setSearchTerm>
|
||||
| ReturnType<typeof setCurrentScript>
|
||||
| ReturnType<typeof setCurrentTask>
|
||||
| ReturnType<typeof setShowInactive>
|
||||
| ReturnType<typeof clearTask>
|
||||
| ReturnType<typeof setRuns>
|
||||
| ReturnType<typeof setLogs>
|
||||
| ReturnType<typeof editTask>
|
||||
| ReturnType<typeof setNewScript>
|
||||
| ReturnType<typeof clearCurrentTask>
|
||||
| ReturnType<typeof removeTask>
|
||||
| ReturnType<typeof addTask>
|
||||
|
||||
// R is the type of the value of the "result" key in normalizr's normalization
|
||||
type TasksSchema<R extends string | string[]> = NormalizedSchema<
|
||||
TaskEntities,
|
||||
R
|
||||
>
|
||||
export const setTasks = (
|
||||
status: RemoteDataState,
|
||||
schema?: TasksSchema<string[]>
|
||||
) =>
|
||||
({
|
||||
type: SET_TASKS,
|
||||
status,
|
||||
schema,
|
||||
} as const)
|
||||
|
||||
export const addTask = (schema: TasksSchema<string>) =>
|
||||
({
|
||||
type: ADD_TASK,
|
||||
schema,
|
||||
} as const)
|
||||
|
||||
export const editTask = (schema: TasksSchema<string>) =>
|
||||
({
|
||||
type: EDIT_TASK,
|
||||
schema,
|
||||
} as const)
|
||||
|
||||
export const removeTask = (id: string) =>
|
||||
({
|
||||
type: REMOVE_TASK,
|
||||
id,
|
||||
} as const)
|
||||
|
||||
export const setCurrentTask = (schema: TasksSchema<string>) =>
|
||||
({
|
||||
type: SET_CURRENT_TASK,
|
||||
schema,
|
||||
} as const)
|
||||
|
||||
export const clearCurrentTask = () =>
|
||||
({
|
||||
type: CLEAR_CURRENT_TASK,
|
||||
} as const)
|
||||
|
||||
export const setTaskOption = (taskOption: {
|
||||
key: TaskOptionKeys
|
||||
value: string
|
||||
}) =>
|
||||
({
|
||||
type: SET_TASK_OPTION,
|
||||
...taskOption,
|
||||
} as const)
|
||||
|
||||
export const setAllTaskOptions = (schema: TasksSchema<string>) =>
|
||||
({
|
||||
type: SET_ALL_TASK_OPTIONS,
|
||||
schema,
|
||||
} as const)
|
||||
|
||||
export const clearTask = () =>
|
||||
({
|
||||
type: CLEAR_TASK,
|
||||
} as const)
|
||||
|
||||
export const setNewScript = (script: string) =>
|
||||
({
|
||||
type: SET_NEW_SCRIPT,
|
||||
script,
|
||||
} as const)
|
||||
|
||||
export const setCurrentScript = (script: string) =>
|
||||
({
|
||||
type: SET_CURRENT_SCRIPT,
|
||||
script,
|
||||
} as const)
|
||||
|
||||
export const setSearchTerm = (searchTerm: string) =>
|
||||
({
|
||||
type: SET_SEARCH_TERM,
|
||||
searchTerm,
|
||||
} as const)
|
||||
|
||||
export const setShowInactive = () =>
|
||||
({
|
||||
type: SET_SHOW_INACTIVE,
|
||||
} as const)
|
||||
|
||||
export const setRuns = (runs: Run[], runStatus: RemoteDataState) =>
|
||||
({
|
||||
type: SET_RUNS,
|
||||
runs,
|
||||
runStatus,
|
||||
} as const)
|
||||
|
||||
export const setLogs = (logs: LogEvent[]) =>
|
||||
({
|
||||
type: SET_LOGS,
|
||||
logs,
|
||||
} as const)
|
|
@ -1,649 +0,0 @@
|
|||
// Libraries
|
||||
import {push, goBack} from 'react-router-redux'
|
||||
import _ from 'lodash'
|
||||
// APIs
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
import {
|
||||
taskNotCreated,
|
||||
tasksFetchFailed,
|
||||
taskDeleteFailed,
|
||||
taskNotFound,
|
||||
taskUpdateFailed,
|
||||
taskUpdateSuccess,
|
||||
taskCreatedSuccess,
|
||||
taskDeleteSuccess,
|
||||
taskCloneSuccess,
|
||||
taskCloneFailed,
|
||||
taskRunSuccess,
|
||||
taskGetFailed,
|
||||
importTaskFailed,
|
||||
importTaskSucceeded,
|
||||
} from 'src/shared/copy/notifications'
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAJAX} from 'src/templates/api'
|
||||
import {addLabelDefaults} from 'src/labels/utils'
|
||||
import {
|
||||
deleteTask as apiDeleteTask,
|
||||
deleteTasksLabel as apiDeleteTasksLabel,
|
||||
getTask as apiGetTask,
|
||||
getTasks as apiGetTasks,
|
||||
getTasksRuns as apiGetTasksRuns,
|
||||
getTasksRunsLogs as apiGetTasksRunsLogs,
|
||||
patchTask as apiPatchTask,
|
||||
postTask as apiPostTask,
|
||||
postTasksLabel as apiPostTasksLabel,
|
||||
postTasksRun as apiPostTasksRun,
|
||||
} from 'src/client'
|
||||
// Actions
|
||||
import {setExportTemplate} from 'src/templates/actions'
|
||||
|
||||
// Constants
|
||||
import * as copy from 'src/shared/copy/notifications'
|
||||
|
||||
// Types
|
||||
import {Label, TaskTemplate, LogEvent, Run, Task, GetState} from 'src/types'
|
||||
import {RemoteDataState} from '@influxdata/clockface'
|
||||
import {Task as ITask} from 'src/client'
|
||||
|
||||
// Utils
|
||||
import {getErrorMessage} from 'src/utils/api'
|
||||
import {insertPreambleInScript} from 'src/shared/utils/insertPreambleInScript'
|
||||
import {TaskOptionKeys, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {taskToTemplate} from 'src/shared/utils/resourceToTemplate'
|
||||
import {isLimitError} from 'src/cloud/utils/limits'
|
||||
import {checkTaskLimits} from 'src/cloud/actions/limits'
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
|
||||
export type Action =
|
||||
| SetNewScript
|
||||
| SetTasks
|
||||
| SetSearchTerm
|
||||
| SetCurrentScript
|
||||
| SetCurrentTask
|
||||
| SetShowInactive
|
||||
| SetTaskInterval
|
||||
| SetTaskCron
|
||||
| ClearTask
|
||||
| SetTaskOption
|
||||
| SetAllTaskOptions
|
||||
| SetRuns
|
||||
| SetLogs
|
||||
| UpdateTask
|
||||
| SetTaskStatus
|
||||
|
||||
type GetStateFunc = GetState
|
||||
|
||||
export interface SetAllTaskOptions {
|
||||
type: 'SET_ALL_TASK_OPTIONS'
|
||||
payload: Task
|
||||
}
|
||||
|
||||
export interface SetTaskStatus {
|
||||
type: 'SET_TASKS_STATUS'
|
||||
payload: {
|
||||
status: RemoteDataState
|
||||
}
|
||||
}
|
||||
|
||||
export interface ClearTask {
|
||||
type: 'CLEAR_TASK'
|
||||
}
|
||||
|
||||
export interface SetTaskInterval {
|
||||
type: 'SET_TASK_INTERVAL'
|
||||
payload: {
|
||||
interval: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetTaskCron {
|
||||
type: 'SET_TASK_CRON'
|
||||
payload: {
|
||||
cron: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetNewScript {
|
||||
type: 'SET_NEW_SCRIPT'
|
||||
payload: {
|
||||
script: string
|
||||
}
|
||||
}
|
||||
export interface SetCurrentScript {
|
||||
type: 'SET_CURRENT_SCRIPT'
|
||||
payload: {
|
||||
script: string
|
||||
}
|
||||
}
|
||||
export interface SetCurrentTask {
|
||||
type: 'SET_CURRENT_TASK'
|
||||
payload: {
|
||||
task: Task
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetTasks {
|
||||
type: 'SET_TASKS'
|
||||
payload: {
|
||||
tasks: Task[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetSearchTerm {
|
||||
type: 'SET_SEARCH_TERM'
|
||||
payload: {
|
||||
searchTerm: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetShowInactive {
|
||||
type: 'SET_SHOW_INACTIVE'
|
||||
payload: {}
|
||||
}
|
||||
|
||||
export interface SetTaskOption {
|
||||
type: 'SET_TASK_OPTION'
|
||||
payload: {
|
||||
key: TaskOptionKeys
|
||||
value: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetRuns {
|
||||
type: 'SET_RUNS'
|
||||
payload: {
|
||||
runs: Run[]
|
||||
runStatus: RemoteDataState
|
||||
}
|
||||
}
|
||||
|
||||
export interface SetLogs {
|
||||
type: 'SET_LOGS'
|
||||
payload: {
|
||||
logs: LogEvent[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateTask {
|
||||
type: 'UPDATE_TASK'
|
||||
payload: {
|
||||
task: Task
|
||||
}
|
||||
}
|
||||
|
||||
export const addDefaults = (task: ITask): Task => {
|
||||
return {
|
||||
...task,
|
||||
labels: (task.labels || []).map(addLabelDefaults),
|
||||
}
|
||||
}
|
||||
|
||||
export const setTaskOption = (taskOption: {
|
||||
key: TaskOptionKeys
|
||||
value: string
|
||||
}): SetTaskOption => ({
|
||||
type: 'SET_TASK_OPTION',
|
||||
payload: taskOption,
|
||||
})
|
||||
|
||||
export const setTasksStatus = (status: RemoteDataState): SetTaskStatus => ({
|
||||
type: 'SET_TASKS_STATUS',
|
||||
payload: {status},
|
||||
})
|
||||
|
||||
export const setAllTaskOptions = (task: Task): SetAllTaskOptions => ({
|
||||
type: 'SET_ALL_TASK_OPTIONS',
|
||||
payload: task,
|
||||
})
|
||||
|
||||
export const clearTask = (): ClearTask => ({
|
||||
type: 'CLEAR_TASK',
|
||||
})
|
||||
|
||||
export const setNewScript = (script: string): SetNewScript => ({
|
||||
type: 'SET_NEW_SCRIPT',
|
||||
payload: {script},
|
||||
})
|
||||
|
||||
export const setCurrentScript = (script: string): SetCurrentScript => ({
|
||||
type: 'SET_CURRENT_SCRIPT',
|
||||
payload: {script},
|
||||
})
|
||||
|
||||
export const setCurrentTask = (task: Task): SetCurrentTask => ({
|
||||
type: 'SET_CURRENT_TASK',
|
||||
payload: {task},
|
||||
})
|
||||
|
||||
export const setTasks = (tasks: Task[]): SetTasks => ({
|
||||
type: 'SET_TASKS',
|
||||
payload: {tasks},
|
||||
})
|
||||
|
||||
export const setSearchTerm = (searchTerm: string): SetSearchTerm => ({
|
||||
type: 'SET_SEARCH_TERM',
|
||||
payload: {searchTerm},
|
||||
})
|
||||
|
||||
export const setShowInactive = (): SetShowInactive => ({
|
||||
type: 'SET_SHOW_INACTIVE',
|
||||
payload: {},
|
||||
})
|
||||
|
||||
export const setRuns = (runs: Run[], runStatus: RemoteDataState): SetRuns => ({
|
||||
type: 'SET_RUNS',
|
||||
payload: {runs, runStatus},
|
||||
})
|
||||
|
||||
export const setLogs = (logs: LogEvent[]): SetLogs => ({
|
||||
type: 'SET_LOGS',
|
||||
payload: {logs},
|
||||
})
|
||||
|
||||
export const updateTask = (task: Task): UpdateTask => ({
|
||||
type: 'UPDATE_TASK',
|
||||
payload: {task},
|
||||
})
|
||||
|
||||
// Thunks
|
||||
export const getTasks = () => async (
|
||||
dispatch,
|
||||
getState: GetStateFunc
|
||||
): Promise<void> => {
|
||||
try {
|
||||
dispatch(setTasksStatus(RemoteDataState.Loading))
|
||||
|
||||
const org = getOrg(getState())
|
||||
const resp = await apiGetTasks({query: {orgID: org.id}})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const tasks = resp.data.tasks.map(task => addDefaults(task))
|
||||
|
||||
dispatch(setTasks(tasks))
|
||||
dispatch(setTasksStatus(RemoteDataState.Done))
|
||||
} catch (e) {
|
||||
dispatch(setTasksStatus(RemoteDataState.Error))
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(tasksFetchFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const addTaskLabelAsync = (taskID: string, label: Label) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const postResp = await apiPostTasksLabel({
|
||||
taskID,
|
||||
data: {labelID: label.id},
|
||||
})
|
||||
|
||||
if (postResp.status !== 201) {
|
||||
throw new Error(postResp.data.message)
|
||||
}
|
||||
|
||||
const resp = await apiGetTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = addDefaults(resp.data)
|
||||
|
||||
dispatch(updateTask(task))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(notify(copy.addTaskLabelFailed()))
|
||||
}
|
||||
}
|
||||
|
||||
export const removeTaskLabelAsync = (taskID: string, label: Label) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const deleteResp = await apiDeleteTasksLabel({taskID, labelID: label.id})
|
||||
if (deleteResp.status !== 204) {
|
||||
throw new Error(deleteResp.data.message)
|
||||
}
|
||||
const resp = await apiGetTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = addDefaults(resp.data)
|
||||
|
||||
dispatch(updateTask(task))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(notify(copy.removeTaskLabelFailed()))
|
||||
}
|
||||
}
|
||||
|
||||
export const updateTaskStatus = (task: Task) => async dispatch => {
|
||||
try {
|
||||
const resp = await apiPatchTask({
|
||||
taskID: task.id,
|
||||
data: {status: task.status},
|
||||
})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(getTasks())
|
||||
dispatch(notify(taskUpdateSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(taskUpdateFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const updateTaskName = (
|
||||
name: string,
|
||||
taskID: string
|
||||
) => async dispatch => {
|
||||
try {
|
||||
const resp = await apiPatchTask({taskID, data: {name}})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(getTasks())
|
||||
dispatch(notify(taskUpdateSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(taskUpdateFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteTask = (task: Task) => async dispatch => {
|
||||
try {
|
||||
const resp = await apiDeleteTask({taskID: task.id})
|
||||
|
||||
if (resp.status !== 204) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(getTasks())
|
||||
dispatch(notify(taskDeleteSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(taskDeleteFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const cloneTask = (task: Task, _) => async dispatch => {
|
||||
try {
|
||||
const resp = await apiGetTask({taskID: task.id})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const postData = addDefaults(resp.data)
|
||||
|
||||
const newTask = await apiPostTask({data: postData})
|
||||
|
||||
if (newTask.status !== 201) {
|
||||
throw new Error(newTask.data.message)
|
||||
}
|
||||
|
||||
dispatch(notify(taskCloneSuccess(task.name)))
|
||||
dispatch(getTasks())
|
||||
dispatch(checkTaskLimits())
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (isLimitError(error)) {
|
||||
dispatch(notify(copy.resourceLimitReached('tasks')))
|
||||
} else {
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(taskCloneFailed(task.name, message)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const selectTaskByID = (id: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const resp = await apiGetTask({taskID: id})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = addDefaults(resp.data)
|
||||
dispatch(setCurrentTask(task))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(goToTasks())
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(taskNotFound(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const setAllTaskOptionsByID = (taskID: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const resp = await apiGetTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = addDefaults(resp.data)
|
||||
dispatch(setAllTaskOptions(task))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(goToTasks())
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(taskNotFound(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const selectTask = (task: Task) => (
|
||||
dispatch,
|
||||
getState: GetStateFunc
|
||||
) => {
|
||||
const org = getOrg(getState())
|
||||
|
||||
dispatch(push(`/orgs/${org.id}/tasks/${task.id}`))
|
||||
}
|
||||
|
||||
export const goToTasks = () => (dispatch, getState: GetStateFunc) => {
|
||||
const org = getOrg(getState())
|
||||
|
||||
dispatch(push(`/orgs/${org.id}/tasks`))
|
||||
}
|
||||
|
||||
export const cancel = () => dispatch => {
|
||||
dispatch(setCurrentTask(null))
|
||||
dispatch(goBack())
|
||||
}
|
||||
|
||||
export const updateScript = () => async (dispatch, getState: GetStateFunc) => {
|
||||
try {
|
||||
const {
|
||||
tasks: {currentScript: script, currentTask: task, taskOptions},
|
||||
} = getState()
|
||||
|
||||
const updatedTask: Partial<Task> & {
|
||||
name: string
|
||||
flux: string
|
||||
token: string
|
||||
} = {
|
||||
flux: script,
|
||||
name: taskOptions.name,
|
||||
offset: taskOptions.offset,
|
||||
token: null,
|
||||
}
|
||||
|
||||
if (taskOptions.taskScheduleType === TaskSchedule.interval) {
|
||||
updatedTask.every = taskOptions.interval
|
||||
updatedTask.cron = null
|
||||
} else {
|
||||
updatedTask.cron = taskOptions.cron
|
||||
updatedTask.every = null
|
||||
}
|
||||
|
||||
const resp = await apiPatchTask({taskID: task.id, data: updatedTask})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(goToTasks())
|
||||
dispatch(setCurrentTask(null))
|
||||
dispatch(notify(taskUpdateSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(taskUpdateFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const saveNewScript = (script: string, preamble: string) => async (
|
||||
dispatch,
|
||||
getState: GetStateFunc
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const fluxScript = await insertPreambleInScript(script, preamble)
|
||||
const org = getOrg(getState())
|
||||
const resp = await apiPostTask({data: {orgID: org.id, flux: fluxScript}})
|
||||
if (resp.status !== 201) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(setNewScript(''))
|
||||
dispatch(clearTask())
|
||||
dispatch(getTasks())
|
||||
dispatch(goToTasks())
|
||||
dispatch(notify(taskCreatedSuccess()))
|
||||
dispatch(checkTaskLimits())
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (isLimitError(error)) {
|
||||
dispatch(notify(copy.resourceLimitReached('tasks')))
|
||||
} else {
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(taskNotCreated(message)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getRuns = (taskID: string) => async (dispatch): Promise<void> => {
|
||||
try {
|
||||
dispatch(setRuns([], RemoteDataState.Loading))
|
||||
dispatch(selectTaskByID(taskID))
|
||||
const resp = await apiGetTasksRuns({taskID})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const runsWithDuration = resp.data.runs.map(run => {
|
||||
const finished = new Date(run.finishedAt)
|
||||
const started = new Date(run.startedAt)
|
||||
|
||||
return {
|
||||
...run,
|
||||
duration: `${runDuration(finished, started)}`,
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(setRuns(runsWithDuration, RemoteDataState.Done))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(taskGetFailed(message)))
|
||||
dispatch(setRuns([], RemoteDataState.Error))
|
||||
}
|
||||
}
|
||||
|
||||
export const runTask = (taskID: string) => async dispatch => {
|
||||
try {
|
||||
const resp = await apiPostTasksRun({taskID})
|
||||
if (resp.status !== 201) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
dispatch(notify(taskRunSuccess()))
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskRunFailed(message)))
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
export const getLogs = (taskID: string, runID: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const resp = await apiGetTasksRunsLogs({taskID, runID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
dispatch(setLogs(resp.data.events))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(setLogs([]))
|
||||
}
|
||||
}
|
||||
|
||||
export const convertToTemplate = (taskID: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
dispatch(setExportTemplate(RemoteDataState.Loading))
|
||||
const resp = await apiGetTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
const task = addDefaults(resp.data)
|
||||
const taskTemplate = taskToTemplate(task)
|
||||
|
||||
dispatch(setExportTemplate(RemoteDataState.Done, taskTemplate))
|
||||
} catch (error) {
|
||||
dispatch(setExportTemplate(RemoteDataState.Error))
|
||||
dispatch(notify(copy.createTemplateFailed(error)))
|
||||
}
|
||||
}
|
||||
|
||||
export const createTaskFromTemplate = (template: TaskTemplate) => async (
|
||||
dispatch,
|
||||
getState: GetStateFunc
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const org = getOrg(getState())
|
||||
|
||||
await createTaskFromTemplateAJAX(template, org.id)
|
||||
|
||||
dispatch(getTasks())
|
||||
dispatch(notify(importTaskSucceeded()))
|
||||
dispatch(checkTaskLimits())
|
||||
} catch (error) {
|
||||
if (isLimitError(error)) {
|
||||
dispatch(notify(copy.resourceLimitReached('tasks')))
|
||||
} else {
|
||||
dispatch(notify(importTaskFailed(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const runDuration = (finishedAt: Date, startedAt: Date): string => {
|
||||
let timeTag = 'seconds'
|
||||
|
||||
if (isNaN(finishedAt.getTime()) || isNaN(startedAt.getTime())) {
|
||||
return ''
|
||||
}
|
||||
let diff = (finishedAt.getTime() - startedAt.getTime()) / 1000
|
||||
|
||||
if (diff > 60) {
|
||||
diff = Math.round(diff / 60)
|
||||
timeTag = 'minutes'
|
||||
}
|
||||
|
||||
return diff + ' ' + timeTag
|
||||
}
|
|
@ -0,0 +1,497 @@
|
|||
// Libraries
|
||||
import {push, goBack} from 'react-router-redux'
|
||||
import {Dispatch} from 'react'
|
||||
import {normalize} from 'normalizr'
|
||||
|
||||
// APIs
|
||||
import * as api from 'src/client'
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAJAX} from 'src/templates/api'
|
||||
|
||||
// Schemas
|
||||
import * as schemas from 'src/schemas'
|
||||
|
||||
// Actions
|
||||
import {setExportTemplate} from 'src/templates/actions'
|
||||
import {notify, Action as NotifyAction} from 'src/shared/actions/notifications'
|
||||
import {
|
||||
addTask,
|
||||
setTasks,
|
||||
editTask,
|
||||
setCurrentTask,
|
||||
setAllTaskOptions,
|
||||
setRuns,
|
||||
setLogs,
|
||||
clearTask,
|
||||
removeTask,
|
||||
setNewScript,
|
||||
clearCurrentTask,
|
||||
Action as TaskAction,
|
||||
} from 'src/tasks/actions/creators'
|
||||
|
||||
// Constants
|
||||
import * as copy from 'src/shared/copy/notifications'
|
||||
|
||||
// Types
|
||||
import {
|
||||
Label,
|
||||
TaskTemplate,
|
||||
Task,
|
||||
GetState,
|
||||
TaskSchedule,
|
||||
RemoteDataState,
|
||||
TaskEntities,
|
||||
} from 'src/types'
|
||||
|
||||
// Utils
|
||||
import {getErrorMessage} from 'src/utils/api'
|
||||
import {insertPreambleInScript} from 'src/shared/utils/insertPreambleInScript'
|
||||
import {taskToTemplate} from 'src/shared/utils/resourceToTemplate'
|
||||
import {isLimitError} from 'src/cloud/utils/limits'
|
||||
import {checkTaskLimits} from 'src/cloud/actions/limits'
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
|
||||
type Action = TaskAction | ExternalActions | ReturnType<typeof getTasks>
|
||||
type ExternalActions = NotifyAction | ReturnType<typeof checkTaskLimits>
|
||||
|
||||
// Thunks
|
||||
export const getTasks = () => async (
|
||||
dispatch: Dispatch<TaskAction | NotifyAction>,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
try {
|
||||
dispatch(setTasks(RemoteDataState.Loading))
|
||||
|
||||
const org = getOrg(getState())
|
||||
const resp = await api.getTasks({query: {orgID: org.id}})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const tasks = normalize<Task, TaskEntities, string[]>(
|
||||
resp.data.tasks,
|
||||
schemas.arrayOfTasks
|
||||
)
|
||||
|
||||
dispatch(setTasks(RemoteDataState.Done, tasks))
|
||||
} catch (error) {
|
||||
dispatch(setTasks(RemoteDataState.Error))
|
||||
const message = getErrorMessage(error)
|
||||
console.error(error)
|
||||
dispatch(notify(copy.tasksFetchFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const addTaskLabel = (taskID: string, label: Label) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const postResp = await api.postTasksLabel({
|
||||
taskID,
|
||||
data: {labelID: label.id},
|
||||
})
|
||||
|
||||
if (postResp.status !== 201) {
|
||||
throw new Error(postResp.data.message)
|
||||
}
|
||||
|
||||
const resp = await api.getTask({taskID})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = normalize<Task, TaskEntities, string>(resp.data, schemas.task)
|
||||
|
||||
dispatch(editTask(task))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(notify(copy.addTaskLabelFailed()))
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteTaskLabel = (taskID: string, label: Label) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const deleteResp = await api.deleteTasksLabel({taskID, labelID: label.id})
|
||||
if (deleteResp.status !== 204) {
|
||||
throw new Error(deleteResp.data.message)
|
||||
}
|
||||
|
||||
const resp = await api.getTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = normalize<Task, TaskEntities, string>(resp.data, schemas.task)
|
||||
|
||||
dispatch(editTask(task))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(notify(copy.removeTaskLabelFailed()))
|
||||
}
|
||||
}
|
||||
|
||||
export const updateTaskStatus = (task: Task) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
) => {
|
||||
try {
|
||||
const resp = await api.patchTask({
|
||||
taskID: task.id,
|
||||
data: {status: task.status},
|
||||
})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const normTask = normalize<Task, TaskEntities, string>(
|
||||
resp.data,
|
||||
schemas.task
|
||||
)
|
||||
|
||||
dispatch(editTask(normTask))
|
||||
dispatch(notify(copy.taskUpdateSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(copy.taskUpdateFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const updateTaskName = (name: string, taskID: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
) => {
|
||||
try {
|
||||
const resp = await api.patchTask({taskID, data: {name}})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const normTask = normalize<Task, TaskEntities, string>(
|
||||
resp.data,
|
||||
schemas.task
|
||||
)
|
||||
|
||||
dispatch(editTask(normTask))
|
||||
dispatch(notify(copy.taskUpdateSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(copy.taskUpdateFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteTask = (taskID: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
) => {
|
||||
try {
|
||||
const resp = await api.deleteTask({taskID})
|
||||
|
||||
if (resp.status !== 204) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(removeTask(taskID))
|
||||
dispatch(notify(copy.taskDeleteSuccess()))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
const message = getErrorMessage(e)
|
||||
dispatch(notify(copy.taskDeleteFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const cloneTask = (task: Task) => async (dispatch: Dispatch<Action>) => {
|
||||
try {
|
||||
const resp = await api.getTask({taskID: task.id})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const newTask = await api.postTask({data: resp.data})
|
||||
|
||||
if (newTask.status !== 201) {
|
||||
throw new Error(newTask.data.message)
|
||||
}
|
||||
|
||||
const normTask = normalize<Task, TaskEntities, string>(
|
||||
resp.data,
|
||||
schemas.task
|
||||
)
|
||||
|
||||
dispatch(notify(copy.taskCloneSuccess(task.name)))
|
||||
dispatch(addTask(normTask))
|
||||
dispatch(checkTaskLimits())
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (isLimitError(error)) {
|
||||
dispatch(notify(copy.resourceLimitReached('tasks')))
|
||||
} else {
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskCloneFailed(task.name, message)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const selectTaskByID = (id: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const resp = await api.getTask({taskID: id})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = normalize<Task, TaskEntities, string>(resp.data, schemas.task)
|
||||
|
||||
dispatch(setCurrentTask(task))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(goToTasks())
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskNotFound(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const setAllTaskOptionsByID = (taskID: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const resp = await api.getTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = normalize<Task, TaskEntities, string>(resp.data, schemas.task)
|
||||
|
||||
dispatch(setAllTaskOptions(task))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(goToTasks())
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskNotFound(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const selectTask = (taskID: string) => (
|
||||
dispatch: Dispatch<Action>,
|
||||
getState: GetState
|
||||
) => {
|
||||
const org = getOrg(getState())
|
||||
|
||||
dispatch(push(`/orgs/${org.id}/tasks/${taskID}`))
|
||||
}
|
||||
|
||||
export const goToTasks = () => (
|
||||
dispatch: Dispatch<Action>,
|
||||
getState: GetState
|
||||
) => {
|
||||
const org = getOrg(getState())
|
||||
|
||||
dispatch(push(`/orgs/${org.id}/tasks`))
|
||||
}
|
||||
|
||||
export const cancel = () => (dispatch: Dispatch<Action>) => {
|
||||
dispatch(clearCurrentTask())
|
||||
dispatch(goBack())
|
||||
}
|
||||
|
||||
export const updateScript = () => async (
|
||||
dispatch: Dispatch<Action>,
|
||||
getState: GetState
|
||||
) => {
|
||||
try {
|
||||
const state = getState()
|
||||
const {
|
||||
tasks: {currentScript: script, currentTask: task, taskOptions},
|
||||
} = state.resources
|
||||
|
||||
const updatedTask: Partial<Task> & {
|
||||
name: string
|
||||
flux: string
|
||||
token: string
|
||||
} = {
|
||||
flux: script,
|
||||
name: taskOptions.name,
|
||||
offset: taskOptions.offset,
|
||||
token: null,
|
||||
}
|
||||
|
||||
if (taskOptions.taskScheduleType === TaskSchedule.interval) {
|
||||
updatedTask.every = taskOptions.interval
|
||||
updatedTask.cron = null
|
||||
} else {
|
||||
updatedTask.cron = taskOptions.cron
|
||||
updatedTask.every = null
|
||||
}
|
||||
|
||||
const resp = await api.patchTask({taskID: task.id, data: updatedTask})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(goToTasks())
|
||||
dispatch(clearCurrentTask())
|
||||
dispatch(notify(copy.taskUpdateSuccess()))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskUpdateFailed(message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const saveNewScript = (script: string, preamble: string) => async (
|
||||
dispatch: Dispatch<Action>,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const fluxScript = await insertPreambleInScript(script, preamble)
|
||||
const org = getOrg(getState())
|
||||
const resp = await api.postTask({data: {orgID: org.id, flux: fluxScript}})
|
||||
if (resp.status !== 201) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(setNewScript(''))
|
||||
dispatch(clearTask())
|
||||
dispatch(goToTasks())
|
||||
dispatch(notify(copy.taskCreatedSuccess()))
|
||||
dispatch(checkTaskLimits())
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (isLimitError(error)) {
|
||||
dispatch(notify(copy.resourceLimitReached('tasks')))
|
||||
} else {
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskNotCreated(message)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getRuns = (taskID: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
dispatch(setRuns([], RemoteDataState.Loading))
|
||||
dispatch(selectTaskByID(taskID))
|
||||
const resp = await api.getTasksRuns({taskID})
|
||||
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const runsWithDuration = resp.data.runs.map(run => {
|
||||
const finished = new Date(run.finishedAt)
|
||||
const started = new Date(run.startedAt)
|
||||
|
||||
return {
|
||||
...run,
|
||||
duration: `${runDuration(finished, started)}`,
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(setRuns(runsWithDuration, RemoteDataState.Done))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskGetFailed(message)))
|
||||
dispatch(setRuns([], RemoteDataState.Error))
|
||||
}
|
||||
}
|
||||
|
||||
export const runTask = (taskID: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
) => {
|
||||
try {
|
||||
const resp = await api.postTasksRun({taskID})
|
||||
if (resp.status !== 201) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(notify(copy.taskRunSuccess()))
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error)
|
||||
dispatch(notify(copy.taskRunFailed(message)))
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
export const getLogs = (taskID: string, runID: string) => async (
|
||||
dispatch: Dispatch<Action>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const resp = await api.getTasksRunsLogs({taskID, runID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
dispatch(setLogs(resp.data.events))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(setLogs([]))
|
||||
}
|
||||
}
|
||||
|
||||
export const convertToTemplate = (taskID: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
dispatch(setExportTemplate(RemoteDataState.Loading))
|
||||
const resp = await api.getTask({taskID})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const {entities, result} = normalize<Task, TaskEntities, string>(
|
||||
resp.data,
|
||||
schemas.task
|
||||
)
|
||||
|
||||
const taskTemplate = taskToTemplate(entities.tasks[result])
|
||||
|
||||
dispatch(setExportTemplate(RemoteDataState.Done, taskTemplate))
|
||||
} catch (error) {
|
||||
dispatch(setExportTemplate(RemoteDataState.Error))
|
||||
dispatch(notify(copy.createTemplateFailed(error)))
|
||||
}
|
||||
}
|
||||
|
||||
export const createTaskFromTemplate = (template: TaskTemplate) => async (
|
||||
dispatch: Dispatch<Action>,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const org = getOrg(getState())
|
||||
|
||||
await createTaskFromTemplateAJAX(template, org.id)
|
||||
|
||||
dispatch(getTasks())
|
||||
dispatch(notify(copy.importTaskSucceeded()))
|
||||
dispatch(checkTaskLimits())
|
||||
} catch (error) {
|
||||
if (isLimitError(error)) {
|
||||
dispatch(notify(copy.resourceLimitReached('tasks')))
|
||||
} else {
|
||||
dispatch(notify(copy.importTaskFailed(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const runDuration = (finishedAt: Date, startedAt: Date): string => {
|
||||
let timeTag = 'seconds'
|
||||
|
||||
if (isNaN(finishedAt.getTime()) || isNaN(startedAt.getTime())) {
|
||||
return ''
|
||||
}
|
||||
let diff = (finishedAt.getTime() - startedAt.getTime()) / 1000
|
||||
|
||||
if (diff > 60) {
|
||||
diff = Math.round(diff / 60)
|
||||
timeTag = 'minutes'
|
||||
}
|
||||
|
||||
return diff + ' ' + timeTag
|
||||
}
|
|
@ -22,7 +22,7 @@ const setup = (override = {}) => {
|
|||
onFilterChange: jest.fn(),
|
||||
onUpdate: jest.fn(),
|
||||
onAddTaskLabel: jest.fn(),
|
||||
onRemoveTaskLabel: jest.fn(),
|
||||
onDeleteTaskLabel: jest.fn(),
|
||||
onCreateLabel: jest.fn(),
|
||||
labels: [], // all labels
|
||||
...override,
|
||||
|
|
|
@ -17,8 +17,12 @@ import InlineLabels from 'src/shared/components/inlineLabels/InlineLabels'
|
|||
import LastRunTaskStatus from 'src/shared/components/lastRunTaskStatus/LastRunTaskStatus'
|
||||
|
||||
// Actions
|
||||
import {addTaskLabelAsync, removeTaskLabelAsync} from 'src/tasks/actions'
|
||||
import {createLabel as createLabelAsync} from 'src/labels/actions'
|
||||
import {
|
||||
addTaskLabel,
|
||||
deleteTaskLabel,
|
||||
selectTask,
|
||||
} from 'src/tasks/actions/thunks'
|
||||
import {createLabel} from 'src/labels/actions'
|
||||
|
||||
// Selectors
|
||||
import {viewableLabels} from 'src/labels/selectors'
|
||||
|
@ -34,7 +38,7 @@ interface PassedProps {
|
|||
task: Task
|
||||
onActivate: (task: Task) => void
|
||||
onDelete: (task: Task) => void
|
||||
onSelect: (task: Task) => void
|
||||
onSelect: typeof selectTask
|
||||
onClone: (task: Task) => void
|
||||
onRunTask: (taskID: string) => void
|
||||
onUpdate: (name: string, taskID: string) => void
|
||||
|
@ -46,9 +50,9 @@ interface StateProps {
|
|||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onAddTaskLabel: typeof addTaskLabelAsync
|
||||
onRemoveTaskLabel: typeof removeTaskLabelAsync
|
||||
onCreateLabel: typeof createLabelAsync
|
||||
onAddTaskLabel: typeof addTaskLabel
|
||||
onDeleteTaskLabel: typeof deleteTaskLabel
|
||||
onCreateLabel: typeof createLabel
|
||||
}
|
||||
|
||||
type Props = PassedProps & StateProps & DispatchProps
|
||||
|
@ -139,7 +143,7 @@ export class TaskCard extends PureComponent<Props & WithRouterProps> {
|
|||
private handleNameClick = (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
this.props.onSelect(this.props.task)
|
||||
this.props.onSelect(this.props.task.id)
|
||||
}
|
||||
|
||||
private handleViewRuns = () => {
|
||||
|
@ -190,9 +194,9 @@ export class TaskCard extends PureComponent<Props & WithRouterProps> {
|
|||
}
|
||||
|
||||
private handleRemoveLabel = (label: Label) => {
|
||||
const {task, onRemoveTaskLabel} = this.props
|
||||
const {task, onDeleteTaskLabel} = this.props
|
||||
|
||||
onRemoveTaskLabel(task.id, label)
|
||||
onDeleteTaskLabel(task.id, label)
|
||||
}
|
||||
|
||||
private handleCreateLabel = (label: Label) => {
|
||||
|
@ -239,9 +243,9 @@ const mstp = ({labels}: AppState): StateProps => {
|
|||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
onCreateLabel: createLabelAsync,
|
||||
onAddTaskLabel: addTaskLabelAsync,
|
||||
onRemoveTaskLabel: removeTaskLabelAsync,
|
||||
onCreateLabel: createLabel,
|
||||
onAddTaskLabel: addTaskLabel,
|
||||
onDeleteTaskLabel: deleteTaskLabel,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, PassedProps>(
|
||||
|
|
|
@ -6,7 +6,7 @@ import {connect} from 'react-redux'
|
|||
import ExportOverlay from 'src/shared/components/ExportOverlay'
|
||||
|
||||
// Actions
|
||||
import {convertToTemplate as convertToTemplateAction} from 'src/tasks/actions'
|
||||
import {convertToTemplate as convertToTemplateAction} from 'src/tasks/actions/thunks'
|
||||
import {clearExportTemplate as clearExportTemplateAction} from 'src/templates/actions'
|
||||
|
||||
// Types
|
||||
|
|
|
@ -25,8 +25,7 @@ import {
|
|||
AlignItems,
|
||||
ComponentSize,
|
||||
} from '@influxdata/clockface'
|
||||
import {ResourceType} from 'src/types'
|
||||
import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {ResourceType, TaskOptions, TaskSchedule} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
taskOptions: TaskOptions
|
||||
|
|
|
@ -21,31 +21,34 @@ interface Props {
|
|||
|
||||
export default class TaskHeader extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {onCancel, onSave, title} = this.props
|
||||
return (
|
||||
<Page.Header fullWidth={true}>
|
||||
<Page.HeaderLeft>
|
||||
<PageTitleWithOrg title={this.props.title} />
|
||||
<PageTitleWithOrg title={title} />
|
||||
</Page.HeaderLeft>
|
||||
<Page.HeaderRight>
|
||||
<Button
|
||||
color={ComponentColor.Default}
|
||||
text="Cancel"
|
||||
onClick={this.props.onCancel}
|
||||
onClick={onCancel}
|
||||
testID="task-cancel-btn"
|
||||
/>
|
||||
<Button
|
||||
color={ComponentColor.Success}
|
||||
text="Save"
|
||||
status={
|
||||
this.props.canSubmit
|
||||
? ComponentStatus.Default
|
||||
: ComponentStatus.Disabled
|
||||
}
|
||||
onClick={this.props.onSave}
|
||||
status={this.status}
|
||||
onClick={onSave}
|
||||
testID="task-save-btn"
|
||||
/>
|
||||
</Page.HeaderRight>
|
||||
</Page.Header>
|
||||
)
|
||||
}
|
||||
|
||||
private get status() {
|
||||
return this.props.canSubmit
|
||||
? ComponentStatus.Default
|
||||
: ComponentStatus.Disabled
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import TemplateBrowserEmpty from 'src/tasks/components/TemplateBrowserEmpty'
|
|||
import GetResources from 'src/shared/components/GetResources'
|
||||
|
||||
// Actions
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAction} from 'src/tasks/actions'
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAction} from 'src/tasks/actions/thunks'
|
||||
import {getTemplateByID} from 'src/templates/actions'
|
||||
|
||||
// Types
|
||||
|
|
|
@ -9,7 +9,7 @@ import ImportOverlay from 'src/shared/components/ImportOverlay'
|
|||
import {invalidJSON} from 'src/shared/copy/notifications'
|
||||
|
||||
// Actions
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAction} from 'src/tasks/actions/'
|
||||
import {createTaskFromTemplate as createTaskFromTemplateAction} from 'src/tasks/actions/thunks'
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
||||
// Types
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {connect} from 'react-redux'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
|
||||
|
@ -19,7 +18,7 @@ import {
|
|||
} from '@influxdata/clockface'
|
||||
|
||||
// Actions
|
||||
import {getRuns, runTask} from 'src/tasks/actions'
|
||||
import {getRuns, runTask} from 'src/tasks/actions/thunks'
|
||||
|
||||
// Utils
|
||||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
|
@ -145,12 +144,12 @@ class TaskRunsPage extends PureComponent<Props & WithRouterProps, State> {
|
|||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {tasks} = state
|
||||
const {runs, runStatus, currentTask} = state.resources.tasks
|
||||
|
||||
return {
|
||||
runs: tasks.runs,
|
||||
runStatus: tasks.runStatus,
|
||||
currentTask: tasks.currentTask,
|
||||
runs,
|
||||
runStatus,
|
||||
currentTask,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import {Overlay, IndexList} from '@influxdata/clockface'
|
|||
import RunLogsOverlay from 'src/tasks/components/RunLogsList'
|
||||
|
||||
// Actions
|
||||
import {getLogs} from 'src/tasks/actions'
|
||||
import {getLogs} from 'src/tasks/actions/thunks'
|
||||
|
||||
// Types
|
||||
import {ComponentSize, ComponentColor, Button} from '@influxdata/clockface'
|
||||
|
@ -102,9 +102,8 @@ class TaskRunsRow extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {
|
||||
tasks: {logs},
|
||||
} = state
|
||||
const {logs} = state.resources.tasks
|
||||
|
||||
return {logs}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import {Form, Input, Grid} from '@influxdata/clockface'
|
|||
|
||||
// Types
|
||||
import {Columns, InputType} from '@influxdata/clockface'
|
||||
import {TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {TaskSchedule} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
schedule: TaskSchedule
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import memoizeOne from 'memoize-one'
|
||||
|
||||
// Components
|
||||
|
@ -13,11 +12,7 @@ import {Task} from 'src/types'
|
|||
import {SortTypes} from 'src/shared/utils/sort'
|
||||
import {Sort} from '@influxdata/clockface'
|
||||
|
||||
import {
|
||||
addTaskLabelAsync,
|
||||
removeTaskLabelAsync,
|
||||
runTask,
|
||||
} from 'src/tasks/actions'
|
||||
import {selectTask, addTaskLabel, runTask} from 'src/tasks/actions/thunks'
|
||||
import {checkTaskLimits as checkTaskLimitsAction} from 'src/cloud/actions/limits'
|
||||
|
||||
// Selectors
|
||||
|
@ -29,12 +24,11 @@ interface Props {
|
|||
onActivate: (task: Task) => void
|
||||
onDelete: (task: Task) => void
|
||||
onCreate: () => void
|
||||
onSelect: (task: Task) => void
|
||||
onClone: (task: Task) => void
|
||||
onFilterChange: (searchTerm: string) => void
|
||||
totalCount: number
|
||||
onRemoveTaskLabel: typeof removeTaskLabelAsync
|
||||
onAddTaskLabel: typeof addTaskLabelAsync
|
||||
onSelect: typeof selectTask
|
||||
onAddTaskLabel: typeof addTaskLabel
|
||||
onRunTask: typeof runTask
|
||||
onUpdate: (name: string, taskID: string) => void
|
||||
filterComponent?: JSX.Element
|
||||
|
|
|
@ -28,25 +28,28 @@ const FluxMonacoEditor = Loadable({
|
|||
|
||||
// Actions
|
||||
import {
|
||||
updateScript,
|
||||
selectTaskByID,
|
||||
setCurrentScript,
|
||||
cancel,
|
||||
setTaskOption,
|
||||
clearTask,
|
||||
} from 'src/tasks/actions/creators'
|
||||
import {
|
||||
updateScript,
|
||||
selectTaskByID,
|
||||
cancel,
|
||||
setAllTaskOptionsByID,
|
||||
} from 'src/tasks/actions'
|
||||
} from 'src/tasks/actions/thunks'
|
||||
|
||||
// Utils
|
||||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
|
||||
// Types
|
||||
import {
|
||||
AppState,
|
||||
Task,
|
||||
TaskOptions,
|
||||
TaskOptionKeys,
|
||||
TaskSchedule,
|
||||
} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {AppState, Task} from 'src/types'
|
||||
} from 'src/types'
|
||||
|
||||
interface OwnProps {
|
||||
router: InjectedRouter
|
||||
|
@ -165,11 +168,13 @@ class TaskEditPage extends PureComponent<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
const mstp = ({tasks}: AppState): StateProps => {
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {taskOptions, currentScript, currentTask} = state.resources.tasks
|
||||
|
||||
return {
|
||||
taskOptions: tasks.taskOptions,
|
||||
currentScript: tasks.currentScript,
|
||||
currentTask: tasks.currentTask,
|
||||
taskOptions,
|
||||
currentScript,
|
||||
currentTask,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,10 @@ const FluxMonacoEditor = Loadable({
|
|||
// Actions
|
||||
import {
|
||||
setNewScript,
|
||||
saveNewScript,
|
||||
setTaskOption,
|
||||
clearTask,
|
||||
cancel,
|
||||
} from 'src/tasks/actions'
|
||||
} from 'src/tasks/actions/creators'
|
||||
import {saveNewScript, cancel} from 'src/tasks/actions/thunks'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
|
@ -43,12 +42,7 @@ import {
|
|||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
|
||||
// Types
|
||||
import {AppState} from 'src/types'
|
||||
import {
|
||||
TaskOptions,
|
||||
TaskOptionKeys,
|
||||
TaskSchedule,
|
||||
} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {AppState, TaskOptions, TaskOptionKeys, TaskSchedule} from 'src/types'
|
||||
|
||||
interface OwnProps {
|
||||
router: InjectedRouter
|
||||
|
@ -73,6 +67,7 @@ class TaskPage extends PureComponent<Props> {
|
|||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.setTaskOption({
|
||||
key: 'taskScheduleType',
|
||||
|
@ -141,8 +136,8 @@ class TaskPage extends PureComponent<Props> {
|
|||
this.props.setNewScript(script)
|
||||
}
|
||||
|
||||
private handleChangeScheduleType = (schedule: TaskSchedule) => {
|
||||
this.props.setTaskOption({key: 'taskScheduleType', value: schedule})
|
||||
private handleChangeScheduleType = (value: TaskSchedule) => {
|
||||
this.props.setTaskOption({key: 'taskScheduleType', value})
|
||||
}
|
||||
|
||||
private handleSave = () => {
|
||||
|
@ -167,10 +162,13 @@ class TaskPage extends PureComponent<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
const mstp = ({tasks}: AppState): StateProps => {
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {tasks} = state.resources
|
||||
const {taskOptions, newScript} = tasks
|
||||
|
||||
return {
|
||||
taskOptions: tasks.taskOptions,
|
||||
newScript: tasks.newScript,
|
||||
taskOptions,
|
||||
newScript,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
|
||||
// Components
|
||||
import TasksHeader from 'src/tasks/components/TasksHeader'
|
||||
|
@ -24,12 +23,15 @@ import {
|
|||
deleteTask,
|
||||
selectTask,
|
||||
cloneTask,
|
||||
addTaskLabel,
|
||||
runTask,
|
||||
} from 'src/tasks/actions/thunks'
|
||||
|
||||
import {
|
||||
setSearchTerm as setSearchTermAction,
|
||||
setShowInactive as setShowInactiveAction,
|
||||
addTaskLabelAsync,
|
||||
removeTaskLabelAsync,
|
||||
runTask,
|
||||
} from 'src/tasks/actions'
|
||||
} from 'src/tasks/actions/creators'
|
||||
|
||||
import {
|
||||
checkTaskLimits as checkTasksLimitsAction,
|
||||
LimitStatus,
|
||||
|
@ -42,6 +44,9 @@ import {Sort} from '@influxdata/clockface'
|
|||
import {SortTypes} from 'src/shared/utils/sort'
|
||||
import {extractTaskLimits} from 'src/cloud/utils/limits'
|
||||
|
||||
// Selectors
|
||||
import {getAll} from 'src/resources/selectors'
|
||||
|
||||
interface PassedInProps {
|
||||
router: InjectedRouter
|
||||
}
|
||||
|
@ -54,8 +59,7 @@ interface ConnectedDispatchProps {
|
|||
selectTask: typeof selectTask
|
||||
setSearchTerm: typeof setSearchTermAction
|
||||
setShowInactive: typeof setShowInactiveAction
|
||||
onAddTaskLabel: typeof addTaskLabelAsync
|
||||
onRemoveTaskLabel: typeof removeTaskLabelAsync
|
||||
onAddTaskLabel: typeof addTaskLabel
|
||||
onRunTask: typeof runTask
|
||||
checkTaskLimits: typeof checkTasksLimitsAction
|
||||
}
|
||||
|
@ -105,13 +109,13 @@ class TasksPage extends PureComponent<Props, State> {
|
|||
public render(): JSX.Element {
|
||||
const {sortKey, sortDirection, sortType} = this.state
|
||||
const {
|
||||
selectTask,
|
||||
setSearchTerm,
|
||||
updateTaskName,
|
||||
searchTerm,
|
||||
setShowInactive,
|
||||
showInactive,
|
||||
onAddTaskLabel,
|
||||
onRemoveTaskLabel,
|
||||
onRunTask,
|
||||
checkTaskLimits,
|
||||
limitStatus,
|
||||
|
@ -150,9 +154,8 @@ class TasksPage extends PureComponent<Props, State> {
|
|||
onDelete={this.handleDelete}
|
||||
onCreate={this.handleCreateTask}
|
||||
onClone={this.handleClone}
|
||||
onSelect={this.props.selectTask}
|
||||
onSelect={selectTask}
|
||||
onAddTaskLabel={onAddTaskLabel}
|
||||
onRemoveTaskLabel={onRemoveTaskLabel}
|
||||
onRunTask={onRunTask}
|
||||
onFilterChange={setSearchTerm}
|
||||
filterComponent={this.search}
|
||||
|
@ -194,12 +197,11 @@ class TasksPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleDelete = (task: Task) => {
|
||||
this.props.deleteTask(task)
|
||||
this.props.deleteTask(task.id)
|
||||
}
|
||||
|
||||
private handleClone = (task: Task) => {
|
||||
const {tasks} = this.props
|
||||
this.props.cloneTask(task, tasks)
|
||||
this.props.cloneTask(task)
|
||||
}
|
||||
|
||||
private handleCreateTask = () => {
|
||||
|
@ -281,12 +283,15 @@ class TasksPage extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const mstp = ({
|
||||
tasks: {status, list, searchTerm, showInactive},
|
||||
cloud: {limits},
|
||||
}: AppState): ConnectedStateProps => {
|
||||
const mstp = (state: AppState): ConnectedStateProps => {
|
||||
const {
|
||||
resources,
|
||||
cloud: {limits},
|
||||
} = state
|
||||
const {status, searchTerm, showInactive} = resources.tasks
|
||||
|
||||
return {
|
||||
tasks: list,
|
||||
tasks: getAll<Task>(state, ResourceType.Tasks),
|
||||
status: status,
|
||||
searchTerm,
|
||||
showInactive,
|
||||
|
@ -302,8 +307,7 @@ const mdtp: ConnectedDispatchProps = {
|
|||
cloneTask,
|
||||
setSearchTerm: setSearchTermAction,
|
||||
setShowInactive: setShowInactiveAction,
|
||||
onRemoveTaskLabel: removeTaskLabelAsync,
|
||||
onAddTaskLabel: addTaskLabelAsync,
|
||||
onAddTaskLabel: addTaskLabel,
|
||||
onRunTask: runTask,
|
||||
checkTaskLimits: checkTasksLimitsAction,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import {
|
||||
RemoteDataState,
|
||||
ResourceState,
|
||||
TaskOptions,
|
||||
TaskSchedule,
|
||||
} from 'src/types'
|
||||
|
||||
export const initialState = (): ResourceState['tasks'] => ({
|
||||
allIDs: [],
|
||||
byID: {},
|
||||
status: RemoteDataState.NotStarted,
|
||||
newScript: '',
|
||||
currentTask: null,
|
||||
currentScript: '',
|
||||
searchTerm: '',
|
||||
showInactive: true,
|
||||
taskOptions: defaultOptions,
|
||||
runStatus: RemoteDataState.NotStarted,
|
||||
runs: [],
|
||||
logs: [],
|
||||
})
|
||||
|
||||
export const defaultOptions: TaskOptions = {
|
||||
name: '',
|
||||
interval: '',
|
||||
offset: '',
|
||||
cron: '',
|
||||
taskScheduleType: TaskSchedule.unselected,
|
||||
orgID: '',
|
||||
toBucketName: '',
|
||||
toOrgName: '',
|
||||
}
|
|
@ -1,82 +1,94 @@
|
|||
import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
|
||||
// Libraries
|
||||
import {produce} from 'immer'
|
||||
|
||||
// Types
|
||||
import {Action} from 'src/tasks/actions'
|
||||
import {Task, LogEvent, Run} from 'src/types'
|
||||
import {RemoteDataState} from '@influxdata/clockface'
|
||||
import {
|
||||
Action,
|
||||
ADD_TASK,
|
||||
SET_TASKS,
|
||||
CLEAR_TASK,
|
||||
CLEAR_CURRENT_TASK,
|
||||
SET_RUNS,
|
||||
SET_TASK_OPTION,
|
||||
SET_ALL_TASK_OPTIONS,
|
||||
SET_NEW_SCRIPT,
|
||||
SET_CURRENT_SCRIPT,
|
||||
SET_CURRENT_TASK,
|
||||
SET_SEARCH_TERM,
|
||||
SET_SHOW_INACTIVE,
|
||||
SET_LOGS,
|
||||
EDIT_TASK,
|
||||
REMOVE_TASK,
|
||||
} from 'src/tasks/actions/creators'
|
||||
import {ResourceType, ResourceState, TaskSchedule, Task} from 'src/types'
|
||||
|
||||
export interface TasksState {
|
||||
status: RemoteDataState
|
||||
list: Task[]
|
||||
newScript: string
|
||||
currentScript: string
|
||||
currentTask: Task
|
||||
searchTerm: string
|
||||
showInactive: boolean
|
||||
taskOptions: TaskOptions
|
||||
runs: Run[]
|
||||
runStatus: RemoteDataState
|
||||
logs: LogEvent[]
|
||||
}
|
||||
// Utils
|
||||
import {initialState, defaultOptions} from 'src/tasks/reducers/helpers'
|
||||
import {
|
||||
setResource,
|
||||
editResource,
|
||||
removeResource,
|
||||
addResource,
|
||||
} from 'src/resources/reducers/helpers'
|
||||
|
||||
export const defaultTaskOptions: TaskOptions = {
|
||||
name: '',
|
||||
interval: '',
|
||||
offset: '',
|
||||
cron: '',
|
||||
taskScheduleType: TaskSchedule.unselected,
|
||||
orgID: '',
|
||||
toBucketName: '',
|
||||
toOrgName: '',
|
||||
}
|
||||
|
||||
export const defaultState: TasksState = {
|
||||
status: RemoteDataState.NotStarted,
|
||||
list: [],
|
||||
newScript: '',
|
||||
currentTask: null,
|
||||
currentScript: '',
|
||||
searchTerm: '',
|
||||
showInactive: true,
|
||||
taskOptions: defaultTaskOptions,
|
||||
runs: [],
|
||||
runStatus: RemoteDataState.NotStarted,
|
||||
logs: [],
|
||||
}
|
||||
type TasksState = ResourceState['tasks']
|
||||
|
||||
export default (
|
||||
state: TasksState = defaultState,
|
||||
state: TasksState = initialState(),
|
||||
action: Action
|
||||
): TasksState => {
|
||||
switch (action.type) {
|
||||
case 'SET_TASKS':
|
||||
return {
|
||||
...state,
|
||||
list: action.payload.tasks,
|
||||
status: RemoteDataState.Done,
|
||||
}
|
||||
case 'SET_TASKS_STATUS':
|
||||
return {
|
||||
...state,
|
||||
status: action.payload.status,
|
||||
}
|
||||
case 'CLEAR_TASK':
|
||||
return {
|
||||
...state,
|
||||
taskOptions: defaultTaskOptions,
|
||||
currentScript: '',
|
||||
newScript: '',
|
||||
}
|
||||
case 'SET_ALL_TASK_OPTIONS':
|
||||
const {name, every, cron, orgID, offset} = action.payload
|
||||
let taskScheduleType = TaskSchedule.interval
|
||||
if (cron) {
|
||||
taskScheduleType = TaskSchedule.cron
|
||||
): TasksState =>
|
||||
produce(state, draftState => {
|
||||
switch (action.type) {
|
||||
case SET_TASKS: {
|
||||
setResource<Task>(draftState, action, ResourceType.Tasks)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
taskOptions: {
|
||||
case EDIT_TASK: {
|
||||
editResource<Task>(draftState, action, ResourceType.Tasks)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case REMOVE_TASK: {
|
||||
removeResource<Task>(draftState, action)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case ADD_TASK: {
|
||||
addResource<Task>(draftState, action, ResourceType.Tasks)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case CLEAR_TASK: {
|
||||
draftState.taskOptions = defaultOptions
|
||||
draftState.currentScript = ''
|
||||
draftState.newScript = ''
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case CLEAR_CURRENT_TASK: {
|
||||
draftState.currentScript = ''
|
||||
draftState.currentTask = null
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_ALL_TASK_OPTIONS: {
|
||||
const {schema} = action
|
||||
const {entities, result} = schema
|
||||
const {name, every, cron, orgID, offset} = entities.tasks[result]
|
||||
let taskScheduleType = TaskSchedule.interval
|
||||
|
||||
if (cron) {
|
||||
taskScheduleType = TaskSchedule.cron
|
||||
}
|
||||
|
||||
draftState.taskOptions = {
|
||||
...state.taskOptions,
|
||||
name,
|
||||
cron,
|
||||
|
@ -84,43 +96,72 @@ export default (
|
|||
orgID,
|
||||
taskScheduleType,
|
||||
offset,
|
||||
},
|
||||
}
|
||||
case 'SET_TASK_OPTION':
|
||||
const {key, value} = action.payload
|
||||
return {
|
||||
...state,
|
||||
taskOptions: {...state.taskOptions, [key]: value},
|
||||
}
|
||||
case 'SET_NEW_SCRIPT':
|
||||
return {...state, newScript: action.payload.script}
|
||||
case 'SET_CURRENT_SCRIPT':
|
||||
return {...state, currentScript: action.payload.script}
|
||||
case 'SET_CURRENT_TASK':
|
||||
const {task} = action.payload
|
||||
let currentScript = ''
|
||||
if (task) {
|
||||
currentScript = task.flux
|
||||
}
|
||||
return {...state, currentScript, currentTask: task}
|
||||
case 'SET_SEARCH_TERM':
|
||||
const {searchTerm} = action.payload
|
||||
return {...state, searchTerm}
|
||||
case 'SET_SHOW_INACTIVE':
|
||||
return {...state, showInactive: !state.showInactive}
|
||||
case 'UPDATE_TASK': {
|
||||
const {task} = action.payload
|
||||
const tasks = state.list.map(t => (t.id === task.id ? task : t))
|
||||
}
|
||||
|
||||
return {...state, list: tasks}
|
||||
return
|
||||
}
|
||||
|
||||
case SET_TASK_OPTION: {
|
||||
const {key, value} = action
|
||||
|
||||
draftState.taskOptions[`${key}`] = value
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_NEW_SCRIPT: {
|
||||
draftState.newScript = action.script
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_CURRENT_SCRIPT: {
|
||||
draftState.currentScript = action.script
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_CURRENT_TASK: {
|
||||
const {schema} = action
|
||||
const {entities, result} = schema
|
||||
|
||||
const task = entities.tasks[result]
|
||||
|
||||
const currentScript = task.flux || ''
|
||||
|
||||
draftState.currentScript = currentScript
|
||||
draftState.currentTask = task
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_SEARCH_TERM: {
|
||||
const {searchTerm} = action
|
||||
|
||||
draftState.searchTerm = searchTerm
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_SHOW_INACTIVE: {
|
||||
draftState.showInactive = !state.showInactive
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_RUNS: {
|
||||
const {runs, runStatus} = action
|
||||
|
||||
draftState.runs = runs
|
||||
draftState.runStatus = runStatus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case SET_LOGS: {
|
||||
draftState.logs = action.logs
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
case 'SET_RUNS':
|
||||
const {runs, runStatus} = action.payload
|
||||
return {...state, runs, runStatus}
|
||||
case 'SET_LOGS':
|
||||
const {logs} = action.payload
|
||||
return {...state, logs}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
import tasksReducer, {
|
||||
defaultState,
|
||||
defaultTaskOptions,
|
||||
} from 'src/tasks/reducers'
|
||||
import {setTaskOption} from 'src/tasks/actions'
|
||||
import {TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
|
||||
import tasksReducer from 'src/tasks/reducers'
|
||||
import {setTaskOption} from 'src/tasks/actions/creators'
|
||||
|
||||
// Helpers
|
||||
import {initialState, defaultOptions} from 'src/tasks/reducers/helpers'
|
||||
|
||||
// Types
|
||||
import {TaskSchedule} from 'src/types'
|
||||
|
||||
describe('tasksReducer', () => {
|
||||
describe('setTaskOption', () => {
|
||||
it('should not clear the cron property from the task options when interval is selected', () => {
|
||||
const initialState = defaultState
|
||||
const state = initialState()
|
||||
const cron = '0 2 * * *'
|
||||
initialState.taskOptions = {...defaultTaskOptions, cron}
|
||||
state.taskOptions = {...defaultOptions, cron}
|
||||
|
||||
const actual = tasksReducer(
|
||||
initialState,
|
||||
state,
|
||||
setTaskOption({key: 'taskScheduleType', value: TaskSchedule.interval})
|
||||
)
|
||||
|
||||
const expected = {
|
||||
...defaultState,
|
||||
...state,
|
||||
taskOptions: {
|
||||
...defaultTaskOptions,
|
||||
...defaultOptions,
|
||||
taskScheduleType: TaskSchedule.interval,
|
||||
cron,
|
||||
},
|
||||
|
@ -30,19 +32,19 @@ describe('tasksReducer', () => {
|
|||
})
|
||||
|
||||
it('should not clear the interval property from the task options when cron is selected', () => {
|
||||
const initialState = defaultState
|
||||
const state = initialState()
|
||||
const interval = '24h'
|
||||
initialState.taskOptions = {...defaultTaskOptions, interval} // todo(docmerlin): allow for time units larger than 1d, right now h is the longest unit our s
|
||||
state.taskOptions = {...defaultOptions, interval} // todo(docmerlin): allow for time units larger than 1d, right now h is the longest unit our s
|
||||
|
||||
const actual = tasksReducer(
|
||||
initialState,
|
||||
state,
|
||||
setTaskOption({key: 'taskScheduleType', value: TaskSchedule.cron})
|
||||
)
|
||||
|
||||
const expected = {
|
||||
...defaultState,
|
||||
...state,
|
||||
taskOptions: {
|
||||
...defaultTaskOptions,
|
||||
...defaultOptions,
|
||||
taskScheduleType: TaskSchedule.cron,
|
||||
interval,
|
||||
},
|
||||
|
|
|
@ -30,7 +30,7 @@ import * as copy from 'src/shared/copy/notifications'
|
|||
import {client} from 'src/utils/api'
|
||||
import {createDashboardFromTemplate} from 'src/dashboards/actions'
|
||||
import {createVariableFromTemplate} from 'src/variables/actions'
|
||||
import {createTaskFromTemplate} from 'src/tasks/actions'
|
||||
import {createTaskFromTemplate} from 'src/tasks/actions/thunks'
|
||||
|
||||
// Selectors
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
import _, {get} from 'lodash'
|
||||
import {
|
||||
DashboardTemplate,
|
||||
TemplateType,
|
||||
CellIncluded,
|
||||
LabelIncluded,
|
||||
ViewIncluded,
|
||||
TaskTemplate,
|
||||
TemplateBase,
|
||||
Task,
|
||||
VariableTemplate,
|
||||
Variable,
|
||||
} from 'src/types'
|
||||
import {IDashboard, Cell} from '@influxdata/influx'
|
||||
import {client} from 'src/utils/api'
|
||||
// Libraries
|
||||
import {get, isEmpty, flatMap} from 'lodash'
|
||||
import {normalize} from 'normalizr'
|
||||
|
||||
// Schemas
|
||||
import * as schemas from 'src/schemas'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
|
@ -24,9 +15,9 @@ import {
|
|||
hasLabelsRelationships,
|
||||
getLabelRelationships,
|
||||
} from 'src/templates/utils/'
|
||||
import {addDefaults} from 'src/tasks/actions'
|
||||
import {addVariableDefaults} from 'src/variables/actions'
|
||||
import {addLabelDefaults} from 'src/labels/utils'
|
||||
|
||||
// API
|
||||
import {
|
||||
getTask as apiGetTask,
|
||||
|
@ -39,8 +30,25 @@ import {
|
|||
postVariable as apiPostVariable,
|
||||
postVariablesLabel as apiPostVariablesLabel,
|
||||
} from 'src/client'
|
||||
// Create Dashboard Templates
|
||||
import {client} from 'src/utils/api'
|
||||
|
||||
// Types
|
||||
import {
|
||||
DashboardTemplate,
|
||||
TemplateType,
|
||||
CellIncluded,
|
||||
LabelIncluded,
|
||||
ViewIncluded,
|
||||
TaskTemplate,
|
||||
TemplateBase,
|
||||
TaskEntities,
|
||||
Task,
|
||||
VariableTemplate,
|
||||
Variable,
|
||||
} from 'src/types'
|
||||
import {IDashboard, Cell} from '@influxdata/influx'
|
||||
|
||||
// Create Dashboard Templates
|
||||
export const createDashboardFromTemplate = async (
|
||||
template: DashboardTemplate,
|
||||
orgID: string
|
||||
|
@ -103,11 +111,11 @@ const createLabelsFromTemplate = async <T extends TemplateBase>(
|
|||
hasLabelsRelationships(r)
|
||||
)
|
||||
|
||||
if (_.isEmpty(labeledResources)) {
|
||||
if (isEmpty(labeledResources)) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const labelRelationships = _.flatMap(labeledResources, r =>
|
||||
const labelRelationships = flatMap(labeledResources, r =>
|
||||
getLabelRelationships(r)
|
||||
)
|
||||
|
||||
|
@ -129,8 +137,8 @@ const createLabelsFromTemplate = async <T extends TemplateBase>(
|
|||
includedLabels
|
||||
).map(l => ({
|
||||
orgID,
|
||||
name: _.get(l, 'attributes.name', ''),
|
||||
properties: _.get(l, 'attributes.properties', {}),
|
||||
name: get(l, 'attributes.name', ''),
|
||||
properties: get(l, 'attributes.properties', {}),
|
||||
}))
|
||||
|
||||
const promisedLabels = foundLabelsToCreate.map(async lab => {
|
||||
|
@ -299,7 +307,12 @@ export const createTaskFromTemplate = async (
|
|||
throw new Error(postResp.data.message)
|
||||
}
|
||||
|
||||
const postedTask = addDefaults(postResp.data)
|
||||
const {entities, result} = normalize<Task, TaskEntities, string>(
|
||||
postResp.data,
|
||||
schemas.task
|
||||
)
|
||||
|
||||
const postedTask = entities.tasks[result]
|
||||
|
||||
// associate imported label.id with created label
|
||||
const labelMap = await createLabelsFromTemplate(template, orgID)
|
||||
|
@ -312,9 +325,7 @@ export const createTaskFromTemplate = async (
|
|||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
const task = addDefaults(resp.data)
|
||||
|
||||
return task
|
||||
return postedTask
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
RemoteDataState,
|
||||
Telegraf,
|
||||
Scraper,
|
||||
TasksState,
|
||||
} from 'src/types'
|
||||
|
||||
export enum ResourceType {
|
||||
|
@ -42,21 +43,13 @@ export interface TelegrafsState extends NormalizedState<Telegraf> {
|
|||
currentConfig: {status: RemoteDataState; item: string}
|
||||
}
|
||||
|
||||
const {
|
||||
Authorizations,
|
||||
Buckets,
|
||||
Members,
|
||||
Orgs,
|
||||
Telegrafs,
|
||||
Scrapers,
|
||||
} = ResourceType
|
||||
|
||||
// ResourceState defines the types for normalized resources
|
||||
export interface ResourceState {
|
||||
[Authorizations]: NormalizedState<Authorization>
|
||||
[Buckets]: NormalizedState<Bucket>
|
||||
[Members]: NormalizedState<Member>
|
||||
[Orgs]: OrgsState
|
||||
[Telegrafs]: TelegrafsState
|
||||
[Scrapers]: NormalizedState<Scraper>
|
||||
[ResourceType.Authorizations]: NormalizedState<Authorization>
|
||||
[ResourceType.Buckets]: NormalizedState<Bucket>
|
||||
[ResourceType.Members]: NormalizedState<Member>
|
||||
[ResourceType.Orgs]: OrgsState
|
||||
[ResourceType.Telegrafs]: TelegrafsState
|
||||
[ResourceType.Scrapers]: NormalizedState<Scraper>
|
||||
[ResourceType.Tasks]: TasksState
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Types
|
||||
import {
|
||||
Task,
|
||||
Telegraf,
|
||||
Member,
|
||||
Bucket,
|
||||
|
@ -11,7 +12,7 @@ import {
|
|||
// TODO: make these Entities generic
|
||||
|
||||
// AuthEntities defines the result of normalizr's normalization
|
||||
// of the "authorization" resource
|
||||
// of the "authorizations" resource
|
||||
export interface AuthEntities {
|
||||
buckets: {
|
||||
[uuid: string]: Authorization
|
||||
|
@ -19,7 +20,7 @@ export interface AuthEntities {
|
|||
}
|
||||
|
||||
// BucketEntities defines the result of normalizr's normalization
|
||||
// of the "bucket" resource
|
||||
// of the "buckets" resource
|
||||
export interface BucketEntities {
|
||||
buckets: {
|
||||
[uuid: string]: Bucket
|
||||
|
@ -27,7 +28,7 @@ export interface BucketEntities {
|
|||
}
|
||||
|
||||
// MemberEntities defines the result of normalizr's normalization
|
||||
// of the "member" resource
|
||||
// of the "members" resource
|
||||
export interface MemberEntities {
|
||||
members: {
|
||||
[uuid: string]: Member
|
||||
|
@ -35,7 +36,7 @@ export interface MemberEntities {
|
|||
}
|
||||
|
||||
// OrgEntities defines the result of normalizr's normalization
|
||||
// of the "organization" resource
|
||||
// of the "organizations" resource
|
||||
export interface OrgEntities {
|
||||
orgs: {
|
||||
[uuid: string]: Organization
|
||||
|
@ -43,7 +44,7 @@ export interface OrgEntities {
|
|||
}
|
||||
|
||||
// TelegrafEntities defines the result of normalizr's normalization
|
||||
// of the "telegraf" resource
|
||||
// of the "telegrafs" resource
|
||||
export interface TelegrafEntities {
|
||||
telegrafs: {
|
||||
[uuid: string]: Telegraf
|
||||
|
@ -51,9 +52,17 @@ export interface TelegrafEntities {
|
|||
}
|
||||
|
||||
// ScraperEntities defines the result of normalizr's normalization
|
||||
// of the "scraper" resource
|
||||
// of the "scrapers" resource
|
||||
export interface ScraperEntities {
|
||||
scrapers: {
|
||||
[uuid: string]: Scraper
|
||||
}
|
||||
}
|
||||
|
||||
// TaskEntities defines the result of normalizr's normalization
|
||||
// of the "tasks" resource
|
||||
export interface TaskEntities {
|
||||
tasks: {
|
||||
[uuid: string]: Task
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import {Notification} from 'src/types'
|
|||
import {TimeRange} from 'src/types/queries'
|
||||
import {TimeMachinesState} from 'src/timeMachine/reducers'
|
||||
import {AppState as AppPresentationState} from 'src/shared/reducers/app'
|
||||
import {TasksState} from 'src/tasks/reducers'
|
||||
import {RouterState} from 'react-router-redux'
|
||||
import {MeState} from 'src/shared/reducers/me'
|
||||
import {NoteEditorState} from 'src/dashboards/reducers/notes'
|
||||
|
@ -54,7 +53,6 @@ export interface AppState {
|
|||
resources: ResourceState
|
||||
routing: RouterState
|
||||
rules: NotificationRulesState
|
||||
tasks: TasksState
|
||||
telegrafEditorPlugins: TelegrafEditorPluginState
|
||||
telegrafEditorActivePlugins: TelegrafEditorActivePluginState
|
||||
plugins: PluginResourceState
|
||||
|
|
|
@ -1,6 +1,36 @@
|
|||
import {Task as ITask} from 'src/client'
|
||||
import {Label} from 'src/types'
|
||||
import {Label, NormalizedState, Run, RemoteDataState, LogEvent} from 'src/types'
|
||||
|
||||
export interface Task extends ITask {
|
||||
labels?: Label[]
|
||||
}
|
||||
export interface TaskOptions {
|
||||
name: string
|
||||
interval: string
|
||||
cron: string
|
||||
offset: string
|
||||
taskScheduleType: TaskSchedule
|
||||
orgID: string
|
||||
toOrgName: string
|
||||
toBucketName: string
|
||||
}
|
||||
|
||||
export interface TasksState extends NormalizedState<Task> {
|
||||
newScript: string
|
||||
currentScript: string
|
||||
currentTask: Task
|
||||
searchTerm: string
|
||||
showInactive: boolean
|
||||
taskOptions: TaskOptions
|
||||
runs: Run[]
|
||||
runStatus: RemoteDataState
|
||||
logs: LogEvent[]
|
||||
}
|
||||
|
||||
export enum TaskSchedule {
|
||||
interval = 'interval',
|
||||
cron = 'cron',
|
||||
unselected = '',
|
||||
}
|
||||
|
||||
export type TaskOptionKeys = keyof TaskOptions
|
||||
|
|
|
@ -6,25 +6,25 @@ import {getAPIBasepath} from 'src/utils/basepath'
|
|||
const basePath = `${getAPIBasepath()}/api/v2`
|
||||
|
||||
export const getErrorMessage = (e: any) => {
|
||||
let message = get(e, 'response.data.error.message', '')
|
||||
let message = get(e, 'response.data.error.message')
|
||||
|
||||
if (message === '') {
|
||||
message = get(e, 'response.data.error', '')
|
||||
if (!message) {
|
||||
message = get(e, 'response.data.error')
|
||||
}
|
||||
|
||||
if (message === '') {
|
||||
message = get(e, 'response.headers.x-influx-error', '')
|
||||
if (!message) {
|
||||
message = get(e, 'response.headers.x-influx-error')
|
||||
}
|
||||
|
||||
if (message === '') {
|
||||
message = get(e, 'response.data.message', '')
|
||||
if (!message) {
|
||||
message = get(e, 'response.data.message')
|
||||
}
|
||||
|
||||
if (message === '') {
|
||||
message = get(e, 'message', '')
|
||||
if (!message) {
|
||||
message = get(e, 'message')
|
||||
}
|
||||
|
||||
if (message === '') {
|
||||
if (!message) {
|
||||
message = 'unknown error'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,8 @@
|
|||
import _ from 'lodash'
|
||||
// Libraries
|
||||
import {trimEnd} from 'lodash'
|
||||
|
||||
export interface TaskOptions {
|
||||
name: string
|
||||
interval: string
|
||||
cron: string
|
||||
offset: string
|
||||
taskScheduleType: TaskSchedule
|
||||
orgID: string
|
||||
toOrgName: string
|
||||
toBucketName: string
|
||||
}
|
||||
|
||||
export type TaskOptionKeys = keyof TaskOptions
|
||||
|
||||
export enum TaskSchedule {
|
||||
interval = 'interval',
|
||||
cron = 'cron',
|
||||
unselected = '',
|
||||
}
|
||||
// Types
|
||||
import {TaskOptions, TaskSchedule} from 'src/types'
|
||||
|
||||
export const taskOptionsToFluxScript = (options: TaskOptions): string => {
|
||||
let fluxScript = `option task = { \n name: "${options.name}",\n`
|
||||
|
@ -43,7 +28,7 @@ export const addDestinationToFluxScript = (
|
|||
const {toOrgName, toBucketName} = options
|
||||
|
||||
if (toOrgName && toBucketName) {
|
||||
const trimmedScript = _.trimEnd(script)
|
||||
const trimmedScript = trimEnd(script)
|
||||
const trimmedOrgName = toOrgName.trim()
|
||||
const trimmedBucketName = toBucketName.trim()
|
||||
return `${trimmedScript}\n |> to(bucket: "${trimmedBucketName}", org: "${trimmedOrgName}")`
|
||||
|
|
Loading…
Reference in New Issue