fix(ui/org-view): org view polish

* fix(ui/org-view): list actual tasks from api

* fix(ui/org-view): fix dashboard list not rendering

* fix(ui/org-view): fix bucket modal

* feat(dashboards): add updated at column
pull/10616/head
Andrew Watkins 2019-01-03 16:18:14 -08:00 committed by GitHub
parent ac7e9df407
commit 6eca18fc4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 122 additions and 132 deletions

View File

@ -1049,6 +1049,11 @@ paths:
- Dashboards
summary: Get all dashboards
parameters:
- in: query
name: org
description: specifies the organization name of the resource
schema:
type: string
- in: query
name: owner
description: specifies the owner id to return resources for

View File

@ -7123,13 +7123,14 @@ export const DashboardsApiAxiosParamCreator = function (configuration?: Configur
/**
*
* @summary Get all dashboards
* @param {string} [org] specifies the organization name of the resource
* @param {string} [owner] specifies the owner id to return resources for
* @param {'ID' | 'CreatedAt' | 'UpdatedAt'} [sortBy] specifies the owner id to return resources for
* @param {Array<string>} [id] ID list of dashboards to return. If both this and owner are specified, only ids is used.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
dashboardsGet(owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options: any = {}): RequestArgs {
dashboardsGet(org?: string, owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options: any = {}): RequestArgs {
const localVarPath = `/dashboards`;
const localVarUrlObj = url.parse(localVarPath, true);
let baseOptions;
@ -7140,6 +7141,10 @@ export const DashboardsApiAxiosParamCreator = function (configuration?: Configur
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
if (org !== undefined) {
localVarQueryParameter['org'] = org;
}
if (owner !== undefined) {
localVarQueryParameter['owner'] = owner;
}
@ -7411,14 +7416,15 @@ export const DashboardsApiFp = function(configuration?: Configuration) {
/**
*
* @summary Get all dashboards
* @param {string} [org] specifies the organization name of the resource
* @param {string} [owner] specifies the owner id to return resources for
* @param {'ID' | 'CreatedAt' | 'UpdatedAt'} [sortBy] specifies the owner id to return resources for
* @param {Array<string>} [id] ID list of dashboards to return. If both this and owner are specified, only ids is used.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
dashboardsGet(owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise<Dashboards> {
const localVarAxiosArgs = DashboardsApiAxiosParamCreator(configuration).dashboardsGet(owner, sortBy, id, options);
dashboardsGet(org?: string, owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise<Dashboards> {
const localVarAxiosArgs = DashboardsApiAxiosParamCreator(configuration).dashboardsGet(org, owner, sortBy, id, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs = Object.assign(localVarAxiosArgs.options, {url: basePath + localVarAxiosArgs.url})
return axios.request(axiosRequestArgs);
@ -7591,14 +7597,15 @@ export const DashboardsApiFactory = function (configuration?: Configuration, bas
/**
*
* @summary Get all dashboards
* @param {string} [org] specifies the organization name of the resource
* @param {string} [owner] specifies the owner id to return resources for
* @param {'ID' | 'CreatedAt' | 'UpdatedAt'} [sortBy] specifies the owner id to return resources for
* @param {Array<string>} [id] ID list of dashboards to return. If both this and owner are specified, only ids is used.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
dashboardsGet(owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options?: any) {
return DashboardsApiFp(configuration).dashboardsGet(owner, sortBy, id, options)(axios, basePath);
dashboardsGet(org?: string, owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options?: any) {
return DashboardsApiFp(configuration).dashboardsGet(org, owner, sortBy, id, options)(axios, basePath);
},
/**
*
@ -7790,6 +7797,7 @@ export class DashboardsApi extends BaseAPI {
/**
*
* @summary Get all dashboards
* @param {string} [org] specifies the organization name of the resource
* @param {string} [owner] specifies the owner id to return resources for
* @param {'ID' | 'CreatedAt' | 'UpdatedAt'} [sortBy] specifies the owner id to return resources for
* @param {Array<string>} [id] ID list of dashboards to return. If both this and owner are specified, only ids is used.
@ -7797,8 +7805,8 @@ export class DashboardsApi extends BaseAPI {
* @throws {RequiredError}
* @memberof DashboardsApi
*/
public dashboardsGet(owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options?: any) {
return DashboardsApiFp(this.configuration).dashboardsGet(owner, sortBy, id, options)(this.axios, this.basePath);
public dashboardsGet(org?: string, owner?: string, sortBy?: 'ID' | 'CreatedAt' | 'UpdatedAt', id?: Array<string>, options?: any) {
return DashboardsApiFp(this.configuration).dashboardsGet(org, owner, sortBy, id, options)(this.axios, this.basePath);
}
/**

View File

@ -15,7 +15,7 @@ interface Props {
@ErrorHandling
export default class Spinner extends Component<Props> {
public render() {
return <>{this.children}</>
return this.children
}
private get children(): JSX.Element | JSX.Element[] {

View File

@ -1,31 +0,0 @@
import React, {PureComponent} from 'react'
import {SlideToggle, ComponentSize} from 'src/clockface'
interface Props {
dashboardLink: string
defaultDashboardLink: string
onChangeDefault: (link: string) => void
}
class DefaultToggle extends PureComponent<Props> {
public render() {
return (
<SlideToggle
active={this.isActive}
onChange={this.handleChange}
size={ComponentSize.ExtraSmall}
/>
)
}
private handleChange = () => {
this.props.onChangeDefault(this.props.dashboardLink)
}
private get isActive(): boolean {
const {dashboardLink, defaultDashboardLink} = this.props
return dashboardLink === defaultDashboardLink
}
}
export default DefaultToggle

View File

@ -31,6 +31,10 @@ interface Props {
onSetDefaultDashboard: (dashboardLink: string) => void
}
interface DatedDashboard extends Dashboard {
modified: Date
}
interface State {
sortKey: SortKey
sortDirection: Sort
@ -72,15 +76,9 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
columnName={headerKeys[2]}
sortKey={headerKeys[2]}
sort={sortKey === headerKeys[2] ? sortDirection : Sort.None}
width="10%"
width="30%"
onClick={this.handleClickColumn}
/>
<IndexList.HeaderCell
columnName={headerKeys[3]}
sortKey={headerKeys[3]}
width="10%"
alignment={Alignment.Center}
/>
<IndexList.HeaderCell
columnName=""
width="20%"
@ -101,18 +99,17 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
private get sortedRows(): JSX.Element {
const {
dashboards,
onSetDefaultDashboard,
defaultDashboardLink,
onExportDashboard,
onCloneDashboard,
onDeleteDashboard,
} = this.props
const {sortKey, sortDirection} = this.state
if (dashboards.length) {
return (
<SortingHat<Dashboard>
list={dashboards}
<SortingHat<DatedDashboard>
list={this.datedDashboards}
sortKey={sortKey}
direction={sortDirection}
>
@ -122,8 +119,6 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
onCloneDashboard={onCloneDashboard}
onExportDashboard={onExportDashboard}
onDeleteDashboard={onDeleteDashboard}
defaultDashboardLink={defaultDashboardLink}
onSetDefaultDashboard={onSetDefaultDashboard}
/>
)}
</SortingHat>
@ -133,6 +128,13 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
return null
}
private get datedDashboards(): DatedDashboard[] {
return this.props.dashboards.map(d => ({
...d,
modified: new Date(d.meta.updatedAt),
}))
}
private get emptyState(): JSX.Element {
const {onCreateDashboard, searchTerm} = this.props

View File

@ -11,25 +11,26 @@ import {
ComponentSpacer,
IndexList,
} from 'src/clockface'
import DefaultToggle from 'src/dashboards/components/DashboardDefaultToggle'
// Types
import {Dashboard} from 'src/types/v2'
import {Alignment} from 'src/clockface'
import moment from 'moment'
// Constants
import {UPDATED_AT_TIME_FORMAT} from 'src/dashboards/constants'
interface Props {
dashboard: Dashboard
defaultDashboardLink: string
onDeleteDashboard: (dashboard: Dashboard) => void
onCloneDashboard: (dashboard: Dashboard) => void
onExportDashboard: (dashboard: Dashboard) => void
onSetDefaultDashboard: (dashboardLink: string) => void
}
export default class DashboardsIndexTableRow extends PureComponent<Props> {
public render() {
const {dashboard, onSetDefaultDashboard, defaultDashboardLink} = this.props
const {id, name, links} = dashboard
const {dashboard} = this.props
const {id, name} = dashboard
return (
<IndexList.Row key={`dashboard-id--${id}`} disabled={false}>
@ -37,13 +38,8 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
<Link to={`/dashboards/${id}`}>{name}</Link>
</IndexList.Cell>
<IndexList.Cell>You</IndexList.Cell>
<IndexList.Cell>12h Ago</IndexList.Cell>
<IndexList.Cell alignment={Alignment.Center}>
<DefaultToggle
dashboardLink={links.self}
defaultDashboardLink={defaultDashboardLink}
onChangeDefault={onSetDefaultDashboard}
/>
<IndexList.Cell>
{moment(dashboard.meta.updatedAt).format(UPDATED_AT_TIME_FORMAT)}
</IndexList.Cell>
<IndexList.Cell alignment={Alignment.Right} revealOnHover={true}>
<ComponentSpacer align={Alignment.Right}>

View File

@ -9,19 +9,15 @@ import {Dashboard} from 'src/types/v2'
interface Props {
dashboards: Dashboard[]
defaultDashboardLink: string
onDeleteDashboard: (dashboard: Dashboard) => void
onCloneDashboard: (dashboard: Dashboard) => void
onExportDashboard: (dashboard: Dashboard) => void
onSetDefaultDashboard: (dashboardLink: string) => void
}
export default class DashboardsIndexTableRows extends PureComponent<Props> {
public render() {
const {
dashboards,
onSetDefaultDashboard,
defaultDashboardLink,
onExportDashboard,
onCloneDashboard,
onDeleteDashboard,
@ -31,8 +27,6 @@ export default class DashboardsIndexTableRows extends PureComponent<Props> {
<TableRow
key={d.id}
dashboard={d}
onSetDefaultDashboard={onSetDefaultDashboard}
defaultDashboardLink={defaultDashboardLink}
onExportDashboard={onExportDashboard}
onCloneDashboard={onCloneDashboard}
onDeleteDashboard={onDeleteDashboard}

View File

@ -112,3 +112,5 @@ export const DYNAMIC_SOURCE_INFO = {
id: DYNAMIC_SOURCE,
link: '',
}
export const UPDATED_AT_TIME_FORMAT = 'YYYY-MM-DD HH:MM:ss'

View File

@ -31,6 +31,8 @@ export default class BucketList extends PureComponent<Props, State> {
}
public render() {
const {buckets} = this.props
return (
<>
<IndexList>
@ -39,7 +41,13 @@ export default class BucketList extends PureComponent<Props, State> {
<IndexList.HeaderCell columnName="Retention Rule" width="50%" />
</IndexList.Header>
<IndexList.Body columnCount={2} emptyState={this.props.emptyState}>
{this.rows}
{buckets.map(bucket => (
<BucketRow
key={bucket.id}
bucket={bucket}
onEditBucket={this.handleStartEdit}
/>
))}
</IndexList.Body>
</IndexList>
<OverlayTechnology visible={this.isOverlayVisible}>
@ -53,16 +61,6 @@ export default class BucketList extends PureComponent<Props, State> {
)
}
private get rows(): JSX.Element[] {
return this.props.buckets.map(bucket => (
<BucketRow
key={bucket.id}
bucket={bucket}
onEditBucket={this.handleStartEdit}
/>
))
}
private get bucket(): PrettyBucket {
return this.props.buckets.find(b => b.id === this.state.bucketID)
}

View File

@ -1,4 +1,4 @@
import React, {PureComponent, ChangeEvent} from 'react'
import React, {PureComponent, ChangeEvent, FormEvent} from 'react'
// Components
import {
Form,
@ -7,11 +7,11 @@ import {
ComponentColor,
ComponentStatus,
ButtonType,
Grid,
} from 'src/clockface'
import Retention from 'src/organizations/components/Retention'
// Types
import {RetentionRuleTypes} from 'src/types/v2'
import {BucketRetentionRules} from 'src/api'
interface Props {
@ -19,10 +19,10 @@ interface Props {
errorMessage: string
retentionSeconds: number
ruleType: BucketRetentionRules.TypeEnum
onSubmit: () => void
onSubmit: (e: FormEvent<HTMLFormElement>) => void
onCloseModal: () => void
onChangeRetentionRule: (seconds: number) => void
onChangeRuleType: (t: RetentionRuleTypes) => void
onChangeRuleType: (t: BucketRetentionRules.TypeEnum) => void
onChangeInput: (e: ChangeEvent<HTMLInputElement>) => void
nameInputStatus: ComponentStatus
buttonText: string
@ -46,31 +46,45 @@ export default class BucketOverlayForm extends PureComponent<Props> {
return (
<Form onSubmit={onSubmit}>
<Form.Element label="Name" errorMessage={errorMessage}>
<Input
placeholder="Give your bucket a name"
name="name"
autoFocus={true}
value={name}
onChange={onChangeInput}
status={nameInputStatus}
/>
</Form.Element>
<Retention
type={ruleType}
retentionSeconds={retentionSeconds}
onChangeRuleType={onChangeRuleType}
onChangeRetentionRule={onChangeRetentionRule}
/>
<Form.Footer>
<Button
text="Cancel"
color={ComponentColor.Danger}
onClick={onCloseModal}
type={ButtonType.Button}
/>
<Button text={buttonText} color={ComponentColor.Primary} />
</Form.Footer>
<Grid>
<Grid.Row>
<Grid.Column>
<Form.Element label="Name" errorMessage={errorMessage}>
<Input
placeholder="Give your bucket a name"
name="name"
autoFocus={true}
value={name}
onChange={onChangeInput}
status={nameInputStatus}
/>
</Form.Element>
</Grid.Column>
<Grid.Column>
<Retention
type={ruleType}
retentionSeconds={retentionSeconds}
onChangeRuleType={onChangeRuleType}
onChangeRetentionRule={onChangeRetentionRule}
/>
</Grid.Column>
<Grid.Column>
<Form.Footer>
<Button
text="Cancel"
color={ComponentColor.Danger}
onClick={onCloseModal}
type={ButtonType.Button}
/>
<Button
text={buttonText}
color={ComponentColor.Primary}
type={ButtonType.Submit}
/>
</Form.Footer>
</Grid.Column>
</Grid.Row>
</Grid>
</Form>
)
}

View File

@ -1,5 +1,5 @@
// Libraries
import React, {PureComponent, ChangeEvent} from 'react'
import React, {PureComponent, ChangeEvent, FormEvent} from 'react'
// Components
import {
@ -100,8 +100,9 @@ export default class BucketOverlay extends PureComponent<Props, State> {
this.setState({ruleType})
}
private handleSubmit = (): void => {
return this.handleCreateBucket()
private handleSubmit = (e: FormEvent<HTMLFormElement>): void => {
e.preventDefault()
this.handleCreateBucket()
}
private handleCreateBucket = (): void => {

View File

@ -1,6 +1,7 @@
// Libraries
import React, {PureComponent} from 'react'
import {Link} from 'react-router'
import moment from 'moment'
// Components
import {IndexList} from 'src/clockface'
@ -8,6 +9,9 @@ import {IndexList} from 'src/clockface'
// Types
import {Dashboard} from 'src/types/v2'
// Constants
import {UPDATED_AT_TIME_FORMAT} from 'src/dashboards/constants'
interface Props {
dashboards: Dashboard[]
emptyState: JSX.Element
@ -18,8 +22,8 @@ export default class DashboardList extends PureComponent<Props> {
return (
<IndexList>
<IndexList.Header>
<IndexList.HeaderCell columnName="Name" width="75%" />
<IndexList.HeaderCell width="25%" />
<IndexList.HeaderCell columnName="name" width="50%" />
<IndexList.HeaderCell columnName="modified" width="50%" />
</IndexList.Header>
<IndexList.Body columnCount={2} emptyState={this.props.emptyState}>
{this.rows}
@ -29,12 +33,14 @@ export default class DashboardList extends PureComponent<Props> {
}
private get rows(): JSX.Element[] {
return this.props.dashboards.map(dashboard => (
<IndexList.Row key={dashboard.id}>
return this.props.dashboards.map(d => (
<IndexList.Row key={d.id}>
<IndexList.Cell>
<Link to={`/dashboards/${dashboard.id}`}>{dashboard.name}</Link>
<Link to={`/dashboards/${d.id}`}>{d.name}</Link>
</IndexList.Cell>
<IndexList.Cell revealOnHover={true}>
{moment(d.meta.updatedAt).format(UPDATED_AT_TIME_FORMAT)}
</IndexList.Cell>
<IndexList.Cell revealOnHover={true}>DELETE</IndexList.Cell>
</IndexList.Row>
))
}

View File

@ -12,14 +12,13 @@ import {
secondsToDuration,
} from 'src/utils/formatting'
import {RetentionRuleTypes} from 'src/types/v2'
import {BucketRetentionRules} from 'src/api'
interface Props {
retentionSeconds: number
type: BucketRetentionRules.TypeEnum
onChangeRetentionRule: (seconds: number) => void
onChangeRuleType: (type: RetentionRuleTypes) => void
onChangeRuleType: (type: BucketRetentionRules.TypeEnum) => void
}
export default class Retention extends PureComponent<Props> {
@ -33,14 +32,14 @@ export default class Retention extends PureComponent<Props> {
<Radio.Button
active={type === BucketRetentionRules.TypeEnum.Expire}
onClick={this.handleRadioClick}
value={RetentionRuleTypes.Expire}
value={BucketRetentionRules.TypeEnum.Expire}
>
Periodically
</Radio.Button>
<Radio.Button
active={type === null}
onClick={this.handleRadioClick}
value={RetentionRuleTypes.Forever}
value={null}
>
Never
</Radio.Button>
@ -55,7 +54,7 @@ export default class Retention extends PureComponent<Props> {
)
}
private handleRadioClick = (type: RetentionRuleTypes) => {
private handleRadioClick = (type: BucketRetentionRules.TypeEnum) => {
this.props.onChangeRuleType(type)
}

View File

@ -9,7 +9,6 @@ import FilterList from 'src/shared/components/Filter'
// Types
import {Task} from 'src/api'
import {dummyTasks} from 'src/tasks/dummyData'
interface Props {
tasks: Task[]
@ -29,6 +28,7 @@ export default class Tasks extends PureComponent<Props, State> {
public render() {
const {searchTerm} = this.state
const {tasks} = this.props
return (
<>
@ -45,7 +45,7 @@ export default class Tasks extends PureComponent<Props, State> {
<FilterList<Task>
searchTerm={searchTerm}
searchKeys={['name', 'owner.name']}
list={this.tempTasks}
list={tasks}
>
{ts => <TaskList tasks={ts} emptyState={this.emptyState} />}
</FilterList>
@ -53,11 +53,6 @@ export default class Tasks extends PureComponent<Props, State> {
)
}
// TODO: use real tasks
private get tempTasks(): Task[] {
return dummyTasks
}
private handleFilterBlur = (e: ChangeEvent<HTMLInputElement>): void => {
this.setState({searchTerm: e.target.value})
}

View File

@ -107,7 +107,8 @@ export default class BucketOverlay extends PureComponent<Props, State> {
this.setState({ruleType})
}
private handleSubmit = (): void => {
private handleSubmit = (e): void => {
e.preventDefault()
const {onUpdateBucket} = this.props
const {ruleType, bucket} = this.state