Add tabs and descriptions to Templates Page (#14105)
* Add tabs and descriptions to Templates Page * Fixes tests broken by axios upgrade * Add type metadata * add no description placeholderpull/14130/head
parent
5240d5d558
commit
fd458cb33e
|
@ -123,7 +123,7 @@
|
|||
"express": "^4.14.0",
|
||||
"http-proxy-middleware": "^0.18.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^24.1.0",
|
||||
"jest": "^24.8.0",
|
||||
"jsdom": "^9.0.0",
|
||||
"junit-viewer": "^4.11.1",
|
||||
"mocha": "^5.2.0",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
min-height: $form-xs-height;
|
||||
}
|
||||
|
||||
.resource-description--static,
|
||||
.resource-description--preview,
|
||||
.input.resource-description--input > input {
|
||||
font-size: $form-xs-font;
|
||||
|
@ -15,12 +16,14 @@
|
|||
font-family: $ix-text-font;
|
||||
}
|
||||
|
||||
.resource-description--static,
|
||||
.resource-description--preview,
|
||||
.resource-description--input {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.resource-description--static,
|
||||
.resource-description--preview {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
|
@ -29,9 +32,12 @@
|
|||
overflow: hidden;
|
||||
@include no-user-select();
|
||||
color: $g13-mist;
|
||||
line-height: $form-xs-font + $ix-border;
|
||||
}
|
||||
|
||||
.resource-description--preview {
|
||||
transition: color 0.25s ease, background-color 0.25s ease,
|
||||
border-color 0.25s ease;
|
||||
line-height: $form-xs-font + $ix-border;
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
|
|
|
@ -13,7 +13,7 @@ import {ComponentSize} from '@influxdata/clockface'
|
|||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
onUpdate: (name: string) => void
|
||||
onUpdate?: (name: string) => void
|
||||
description: string
|
||||
placeholder?: string
|
||||
}
|
||||
|
@ -35,9 +35,17 @@ class ResourceDescription extends Component<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {description} = this.props
|
||||
const {description, onUpdate} = this.props
|
||||
const {isEditing} = this.state
|
||||
|
||||
if (!onUpdate) {
|
||||
return (
|
||||
<div className="resource-description">
|
||||
<div className="resource-description--static">{description}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isEditing) {
|
||||
return (
|
||||
<div className="resource-description">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {formatDownloadName} from './download'
|
||||
|
||||
describe('formatDownloadName', () => [
|
||||
describe('formatDownloadName', () => {
|
||||
it('formats name correctly', () => {
|
||||
const name1 = 'My Dashboard '
|
||||
const name2 = 'my_dash'
|
||||
|
@ -19,5 +19,5 @@ describe('formatDownloadName', () => [
|
|||
expect(actual1).toEqual(expected1)
|
||||
expect(actual2).toEqual(expected2)
|
||||
expect(actual3).toEqual(expected3)
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Libraries
|
||||
import React, {PureComponent, MouseEvent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {connect} from 'react-redux'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
import {
|
||||
|
@ -50,6 +51,7 @@ class StaticTemplateCard extends PureComponent<Props & WithRouterProps> {
|
|||
<ResourceList.Card
|
||||
testID="template-card"
|
||||
contextMenu={() => this.contextMenu}
|
||||
description={() => this.description}
|
||||
name={() => (
|
||||
<ResourceList.Name
|
||||
onClick={this.handleNameClick}
|
||||
|
@ -59,6 +61,7 @@ class StaticTemplateCard extends PureComponent<Props & WithRouterProps> {
|
|||
inputTestID="template-card--input"
|
||||
/>
|
||||
)}
|
||||
metaData={() => [this.templateType]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -80,6 +83,25 @@ class StaticTemplateCard extends PureComponent<Props & WithRouterProps> {
|
|||
)
|
||||
}
|
||||
|
||||
private get description(): JSX.Element {
|
||||
const {template} = this.props
|
||||
const description = _.get(template, 'content.data.attributes.description')
|
||||
|
||||
return (
|
||||
<ResourceList.Description description={description || 'No description'} />
|
||||
)
|
||||
}
|
||||
|
||||
private get templateType(): JSX.Element {
|
||||
const {template} = this.props
|
||||
|
||||
return (
|
||||
<div className="resource-list--meta-item">
|
||||
{_.get(template, 'content.data.type')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private handleCreate = () => {
|
||||
const {onCreateFromTemplate, name} = this.props
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ interface Props {
|
|||
sortKey: string
|
||||
sortDirection: Sort
|
||||
sortType: SortTypes
|
||||
title?: string
|
||||
onClickColumn: (nextSort: Sort, sortKey: SortKey) => void
|
||||
}
|
||||
|
||||
|
@ -47,8 +46,6 @@ export default class StaticTemplatesList extends PureComponent<Props> {
|
|||
const headerKeys: SortKey[] = ['meta.name']
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Static Templates</h1>
|
||||
<ResourceList>
|
||||
<ResourceList.Header>
|
||||
<ResourceList.Sorter
|
||||
|
@ -66,7 +63,6 @@ export default class StaticTemplatesList extends PureComponent<Props> {
|
|||
{this.rows}
|
||||
</ResourceList.Body>
|
||||
</ResourceList>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ interface Props {
|
|||
sortKey: string
|
||||
sortDirection: Sort
|
||||
sortType: SortTypes
|
||||
title?: string
|
||||
onClickColumn: (nextSort: Sort, sortKey: SortKey) => void
|
||||
}
|
||||
|
||||
|
@ -48,7 +47,6 @@ export default class TemplatesList extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<>
|
||||
{this.header}
|
||||
<ResourceList>
|
||||
<ResourceList.Header>
|
||||
<ResourceList.Sorter
|
||||
|
@ -70,16 +68,6 @@ export default class TemplatesList extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private get header(): JSX.Element {
|
||||
const {title} = this.props
|
||||
|
||||
if (title) {
|
||||
return <h1>{title}</h1>
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private get rows(): JSX.Element[] {
|
||||
const {
|
||||
templates,
|
||||
|
|
|
@ -15,7 +15,14 @@ import GetResources, {ResourceTypes} from 'src/shared/components/GetResources'
|
|||
// Types
|
||||
import {TemplateSummary, AppState} from 'src/types'
|
||||
import {SortTypes} from 'src/shared/utils/sort'
|
||||
import {Sort} from '@influxdata/clockface'
|
||||
import {
|
||||
Sort,
|
||||
Radio,
|
||||
ComponentSpacer,
|
||||
AlignItems,
|
||||
FlexDirection,
|
||||
JustifyContent,
|
||||
} from '@influxdata/clockface'
|
||||
|
||||
import {staticTemplates as statics} from 'src/templates/constants/defaultTemplates'
|
||||
|
||||
|
@ -44,6 +51,7 @@ interface State {
|
|||
sortKey: SortKey
|
||||
sortDirection: Sort
|
||||
sortType: SortTypes
|
||||
activeTab: string
|
||||
}
|
||||
|
||||
type SortKey = 'meta.name'
|
||||
|
@ -58,12 +66,13 @@ class TemplatesPage extends PureComponent<Props, State> {
|
|||
sortKey: 'meta.name',
|
||||
sortDirection: Sort.Ascending,
|
||||
sortType: SortTypes.String,
|
||||
activeTab: 'static-templates',
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {templates, onImport} = this.props
|
||||
const {searchTerm, sortKey, sortDirection, sortType} = this.state
|
||||
const {onImport} = this.props
|
||||
const {activeTab} = this.state
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -73,6 +82,53 @@ class TemplatesPage extends PureComponent<Props, State> {
|
|||
isFullPage={false}
|
||||
filterComponent={() => this.filterComponent}
|
||||
/>
|
||||
<ComponentSpacer
|
||||
direction={FlexDirection.Row}
|
||||
alignItems={AlignItems.Center}
|
||||
justifyContent={JustifyContent.Center}
|
||||
stretchToFitWidth={true}
|
||||
>
|
||||
<Radio>
|
||||
<Radio.Button
|
||||
id="static-templates"
|
||||
active={activeTab === 'static-templates'}
|
||||
value="static-templates"
|
||||
onClick={this.handleClickTab}
|
||||
titleText="Static Templates"
|
||||
>
|
||||
Static Templates
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
id="user-templates"
|
||||
active={activeTab === 'user-templates'}
|
||||
value="user-templates"
|
||||
onClick={this.handleClickTab}
|
||||
titleText="User Templates"
|
||||
>
|
||||
User Templates
|
||||
</Radio.Button>
|
||||
</Radio>
|
||||
</ComponentSpacer>
|
||||
{this.templatesList}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private handleClickTab = val => {
|
||||
this.setState({activeTab: val})
|
||||
}
|
||||
|
||||
private handleClickColumn = (nextSort: Sort, sortKey: SortKey) => {
|
||||
const sortType = SortTypes.String
|
||||
this.setState({sortKey, sortDirection: nextSort, sortType})
|
||||
}
|
||||
|
||||
private get templatesList(): JSX.Element {
|
||||
const {templates, onImport} = this.props
|
||||
const {searchTerm, sortKey, sortDirection, sortType, activeTab} = this.state
|
||||
|
||||
if (activeTab === 'static-templates') {
|
||||
return (
|
||||
<FilterList<StaticTemplate>
|
||||
searchTerm={searchTerm}
|
||||
searchKeys={['template.meta.name', 'labels[].name']}
|
||||
|
@ -81,7 +137,6 @@ class TemplatesPage extends PureComponent<Props, State> {
|
|||
{ts => {
|
||||
return (
|
||||
<StaticTemplatesList
|
||||
title="Static Templates"
|
||||
searchTerm={searchTerm}
|
||||
templates={ts}
|
||||
onFilterChange={this.setSearchTerm}
|
||||
|
@ -94,6 +149,11 @@ class TemplatesPage extends PureComponent<Props, State> {
|
|||
)
|
||||
}}
|
||||
</FilterList>
|
||||
)
|
||||
}
|
||||
|
||||
if (activeTab === 'user-templates') {
|
||||
return (
|
||||
<GetResources resource={ResourceTypes.Labels}>
|
||||
<FilterList<TemplateSummary>
|
||||
searchTerm={searchTerm}
|
||||
|
@ -103,7 +163,6 @@ class TemplatesPage extends PureComponent<Props, State> {
|
|||
{ts => {
|
||||
return (
|
||||
<TemplatesList
|
||||
title="User Templates"
|
||||
searchTerm={searchTerm}
|
||||
templates={ts}
|
||||
onFilterChange={this.setSearchTerm}
|
||||
|
@ -117,13 +176,8 @@ class TemplatesPage extends PureComponent<Props, State> {
|
|||
}}
|
||||
</FilterList>
|
||||
</GetResources>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private handleClickColumn = (nextSort: Sort, sortKey: SortKey) => {
|
||||
const sortType = SortTypes.String
|
||||
this.setState({sortKey, sortDirection: nextSort, sortType})
|
||||
}
|
||||
|
||||
private get filterComponent(): JSX.Element {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import axios, {AxiosResponse} from 'axios'
|
||||
import axios, {AxiosResponse, Method} from 'axios'
|
||||
|
||||
// do not prefix route with basepath, ex. for external links
|
||||
const addBasepath = (url, excludeBasepath): string => {
|
||||
|
@ -11,7 +11,7 @@ interface RequestParams {
|
|||
url?: string | string[]
|
||||
resource?: string | null
|
||||
id?: string | null
|
||||
method?: string
|
||||
method?: Method
|
||||
data?: object | string
|
||||
params?: object
|
||||
headers?: object
|
||||
|
|
Loading…
Reference in New Issue