Show list of tasks to user
parent
7853cff0de
commit
6d02ca5efc
|
@ -86,7 +86,15 @@ class SideNav extends PureComponent<Props> {
|
|||
link: `/logs/${this.sourceParam}`,
|
||||
icon: IconFont.Wood,
|
||||
location: location.pathname,
|
||||
highlightWhen: ['manage-sources'],
|
||||
highlightWhen: ['logs'],
|
||||
},
|
||||
{
|
||||
type: NavItemType.Icon,
|
||||
title: 'Tasks',
|
||||
link: `/tasks/${this.sourceParam}`,
|
||||
icon: IconFont.Wood,
|
||||
location: location.pathname,
|
||||
highlightWhen: ['tasks'],
|
||||
},
|
||||
{
|
||||
type: NavItemType.Icon,
|
||||
|
|
|
@ -16,3 +16,8 @@ export const taskNotCreated = (): Notification => ({
|
|||
...defaultErrorNotification,
|
||||
message: 'Failed to create new task',
|
||||
})
|
||||
|
||||
export const tasksFetchFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Failed to get tasks from server',
|
||||
})
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
import {push} from 'react-router-redux'
|
||||
|
||||
import {submitNewTask} from 'src/tasks/api/v2'
|
||||
import {Task} from 'src/types/v2/tasks'
|
||||
import {submitNewTask, getUserTasks} from 'src/tasks/api/v2'
|
||||
import {getMe} from 'src/shared/apis/v2/user'
|
||||
import {getOrganizations} from 'src/shared/apis/v2/organization'
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
import {taskNotCreated} from 'src/shared/copy/v2/notifications'
|
||||
import {
|
||||
taskNotCreated,
|
||||
tasksFetchFailed,
|
||||
} from 'src/shared/copy/v2/notifications'
|
||||
|
||||
export type Action = SetNewScript
|
||||
export type Action = SetNewScript | SetTasks
|
||||
|
||||
export enum ActionTypes {
|
||||
SetNewScript = 'SET_NEW_SCRIPT',
|
||||
SetTasks = 'SET_TASKS',
|
||||
}
|
||||
|
||||
export interface SetNewScript {
|
||||
|
@ -19,11 +24,51 @@ export interface SetNewScript {
|
|||
}
|
||||
}
|
||||
|
||||
export interface SetTasks {
|
||||
type: ActionTypes.SetTasks
|
||||
payload: {
|
||||
tasks: Task[]
|
||||
}
|
||||
}
|
||||
|
||||
export const setTasks = (tasks: Task[]): SetTasks => ({
|
||||
type: ActionTypes.SetTasks,
|
||||
payload: {tasks},
|
||||
})
|
||||
|
||||
export const setNewScript = (script: string): SetNewScript => ({
|
||||
type: ActionTypes.SetNewScript,
|
||||
payload: {script},
|
||||
})
|
||||
|
||||
export const populateTasks = () => async (
|
||||
dispatch,
|
||||
getState
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const {
|
||||
links: {tasks: url, me: meUrl, orgs: orgsUrl},
|
||||
} = await getState()
|
||||
|
||||
const orgs = await getOrganizations(orgsUrl)
|
||||
|
||||
const user = await getMe(meUrl)
|
||||
const tasks = await getUserTasks(url, user)
|
||||
|
||||
const mappedTasks = tasks.map(task => {
|
||||
return {
|
||||
...task,
|
||||
organization: orgs.find(org => org.id === task.organizationId),
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(setTasks(mappedTasks))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(notify(tasksFetchFailed()))
|
||||
}
|
||||
}
|
||||
|
||||
export const saveNewScript = () => async (
|
||||
dispatch,
|
||||
getState
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
import AJAX from 'src/utils/ajax'
|
||||
|
||||
export const submitNewTask = (url, owner, org, flux) => {
|
||||
const data = {
|
||||
export const submitNewTask = async (url, owner, org, flux) => {
|
||||
const request = {
|
||||
flux,
|
||||
organizationId: org.id,
|
||||
status: 'enabled',
|
||||
status: 'active',
|
||||
owner,
|
||||
}
|
||||
|
||||
return AJAX({url, data, method: 'POST'})
|
||||
const {data} = await AJAX({url, data: request, method: 'POST'})
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export const getUserTasks = async (url, user) => {
|
||||
const completeUrl = `${url}?user=${user.id}`
|
||||
|
||||
const {data} = await AJAX({url: completeUrl})
|
||||
|
||||
return data
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
import {Task} from 'src/types/v2/tasks'
|
||||
import {ComponentColor, ComponentSize, Button, SlideToggle} from 'src/clockface'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
||||
interface Props {
|
||||
task: Task
|
||||
}
|
||||
|
||||
export default class TaskRow extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<tr>
|
||||
<td>{this.name}</td>
|
||||
<td>{this.organizationName}</td>
|
||||
<td>
|
||||
<SlideToggle active={true} />
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
color={ComponentColor.Danger}
|
||||
text="Delete"
|
||||
size={ComponentSize.Medium}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
private get name(): string {
|
||||
const {task} = this.props
|
||||
|
||||
return task.name
|
||||
}
|
||||
|
||||
private get organizationName(): string {
|
||||
const {task} = this.props
|
||||
|
||||
return getDeep(task, 'organization.name', '')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {Page} from 'src/pageLayout'
|
||||
import {Button, ComponentColor, IconFont} from 'src/clockface'
|
||||
|
||||
interface Props {
|
||||
onCreateTask: () => void
|
||||
}
|
||||
|
||||
export default class TasksHeader extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {onCreateTask} = this.props
|
||||
|
||||
return (
|
||||
<Page.Header fullWidth={true}>
|
||||
<Page.Header.Left>
|
||||
<Page.Title title="Tasks" />
|
||||
</Page.Header.Left>
|
||||
<Page.Header.Right>
|
||||
<Button
|
||||
color={ComponentColor.Primary}
|
||||
onClick={onCreateTask}
|
||||
icon={IconFont.Plus}
|
||||
text="Create Task"
|
||||
titleText="Create a new task"
|
||||
/>
|
||||
</Page.Header.Right>
|
||||
</Page.Header>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {Task} from 'src/types/v2/tasks'
|
||||
|
||||
import TaskRow from 'src/tasks/components/TaskRow'
|
||||
|
||||
interface Props {
|
||||
tasks: Task[]
|
||||
}
|
||||
|
||||
export default class TasksList extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
<th>Enabled</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{this.tasks}</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
|
||||
private get tasks(): JSX.Element[] {
|
||||
const {tasks} = this.props
|
||||
|
||||
return tasks.map(task => <TaskRow key={`task-${task.id}`} task={task} />)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import _ from 'lodash'
|
||||
import React, {PureComponent} from 'react'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
import {connect} from 'react-redux'
|
||||
import FluxEditor from 'src/flux/components/v2/FluxEditor'
|
||||
|
||||
|
@ -15,6 +16,10 @@ import {
|
|||
} from 'src/clockface'
|
||||
import {Page} from 'src/pageLayout'
|
||||
|
||||
interface PassedInProps {
|
||||
router: InjectedRouter
|
||||
}
|
||||
|
||||
interface ConnectStateProps {
|
||||
newScript: string
|
||||
tasksLink: string
|
||||
|
@ -26,7 +31,7 @@ interface ConnectDispatchProps {
|
|||
}
|
||||
|
||||
class TaskPage extends PureComponent<
|
||||
{} & ConnectStateProps & ConnectDispatchProps
|
||||
PassedInProps & ConnectStateProps & ConnectDispatchProps
|
||||
> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -45,6 +50,7 @@ class TaskPage extends PureComponent<
|
|||
<Button
|
||||
color={ComponentColor.Default}
|
||||
text="Cancel"
|
||||
onClick={this.handleCancel}
|
||||
size={ComponentSize.Medium}
|
||||
/>
|
||||
<Button
|
||||
|
@ -83,6 +89,10 @@ class TaskPage extends PureComponent<
|
|||
private handleSave = () => {
|
||||
this.props.saveNewScript()
|
||||
}
|
||||
|
||||
private handleCancel = () => {
|
||||
this.props.router.push('/tasks')
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = ({
|
||||
|
|
|
@ -1,40 +1,57 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
|
||||
import {Page} from 'src/pageLayout'
|
||||
import {Button, ComponentColor, IconFont} from 'src/clockface'
|
||||
import TasksHeader from 'src/tasks/components/TasksHeader'
|
||||
import TasksList from 'src/tasks/components/TasksList'
|
||||
|
||||
interface Props {
|
||||
import {populateTasks} from 'src/tasks/actions/v2'
|
||||
import {Task} from 'src/types/v2/tasks'
|
||||
|
||||
interface PassedInProps {
|
||||
router: InjectedRouter
|
||||
}
|
||||
|
||||
interface ConnectedDispatchProps {
|
||||
populateTasks: typeof populateTasks
|
||||
}
|
||||
|
||||
interface ConnectedStateProps {
|
||||
tasks: Task[]
|
||||
}
|
||||
|
||||
type Props = ConnectedDispatchProps & PassedInProps & ConnectedStateProps
|
||||
|
||||
class TasksPage extends PureComponent<Props> {
|
||||
public render(): JSX.Element {
|
||||
const {tasks} = this.props
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<Page.Header fullWidth={true}>
|
||||
<Page.Header.Left>
|
||||
<Page.Title title="Tasks" />
|
||||
</Page.Header.Left>
|
||||
<Page.Header.Right>
|
||||
<Button
|
||||
color={ComponentColor.Primary}
|
||||
onClick={this.handleCreateTask}
|
||||
icon={IconFont.Plus}
|
||||
text="Create Task"
|
||||
titleText="Create a new task"
|
||||
/>
|
||||
</Page.Header.Right>
|
||||
</Page.Header>
|
||||
YO!
|
||||
<TasksHeader onCreateTask={this.handleCreateTask} />
|
||||
<TasksList tasks={tasks} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.populateTasks()
|
||||
}
|
||||
|
||||
private handleCreateTask = () => {
|
||||
const {router} = this.props
|
||||
router.push('/tasks/new')
|
||||
}
|
||||
}
|
||||
|
||||
export default TasksPage
|
||||
const mstp = ({tasks: {tasks}}): ConnectedStateProps => {
|
||||
return {tasks}
|
||||
}
|
||||
|
||||
const mdtp: ConnectedDispatchProps = {
|
||||
populateTasks,
|
||||
}
|
||||
|
||||
export default connect(mstp, mdtp)(TasksPage) as React.ComponentClass<
|
||||
PassedInProps
|
||||
>
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
import {Action, ActionTypes} from 'src/tasks/actions/v2'
|
||||
import {Task} from 'src/types/v2/tasks'
|
||||
|
||||
export interface State {
|
||||
newScript: string
|
||||
tasks: Task[]
|
||||
}
|
||||
|
||||
const defaultState: State = {
|
||||
newScript: '',
|
||||
tasks: [],
|
||||
}
|
||||
|
||||
export default (state: State = defaultState, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case ActionTypes.SetNewScript:
|
||||
return {...state, newScript: action.payload.script}
|
||||
case ActionTypes.SetTasks:
|
||||
return {...state, tasks: action.payload.tasks}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
export interface Task {
|
||||
id: string
|
||||
name: string
|
||||
organizationId: string
|
||||
organization: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
owner: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue