Skip to content

Commit

Permalink
Merge pull request #13875 from influxdata/fix-members-resource-list
Browse files Browse the repository at this point in the history
Update members to use ResourceList instead of IndexList
  • Loading branch information
Palakp41 authored May 10, 2019
2 parents 1cfdfb4 + 4ae929b commit 5d99b0b
Show file tree
Hide file tree
Showing 15 changed files with 366 additions and 259 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Editable Name for Resource Cards
------------------------------------------------------------------------------
*/

$resource-name-font-size: 17px;
$resource-name-font-weight: 600;

.resource-editable-name > a,
.input.resource-editable-name--input > input {
font-size: $resource-name-font-size;
font-weight: $resource-name-font-weight;
font-family: $ix-text-font;
}

.resource-editable-name > a {
display: inline-block;
white-space: nowrap;
line-height: $form-xs-height;
}

.resource-editable-name {
height: $form-xs-height;
position: relative;
display: inline-flex;
flex-wrap: nowrap;
margin-right: $ix-marg-a;
}

.input.resource-editable-name--input {
position: absolute;
top: 0;
left: 0;
width: 100%;
}

/* Ensure placeholder text matches font weight of title */
.input.resource-editable-name--input > input {
&::-webkit-input-placeholder {
font-weight: $resource-name-font-weight !important;
}
&::-moz-placeholder {
font-weight: $resource-name-font-weight !important;
}
&:-ms-input-placeholder {
font-weight: $resource-name-font-weight !important;
}
&:-moz-placeholder {
font-weight: $resource-name-font-weight !important;
}
}

/* Edit button hover behavior */
.resource-editable-name--toggle {
font-size: $resource-name-font-size * 0.75;
transform: translateY(-10%);
padding: $ix-marg-a;
display: inline-block;
margin-left: $ix-marg-b;
transition: color 0.25s ease, opacity 0.25s ease, width 0.25s ease;
opacity: 0;
width: 0;
color: $g11-sidewalk;

&:hover {
cursor: pointer;
color: $g15-platinum;
}
}

.resource-editable-name:hover,
.resource-editable-name--editing {
.resource-editable-name--toggle {
opacity: 1;
width: $ix-marg-b + $ix-marg-c;
}
}
172 changes: 172 additions & 0 deletions ui/src/clockface/components/resource_list/ResourceEditableName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Libraries
import React, {Component, KeyboardEvent, ChangeEvent, MouseEvent} from 'react'
import classnames from 'classnames'

// Components
import {Input, SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import {ClickOutside} from 'src/shared/components/ClickOutside'

// Types
import {ComponentSize} from '@influxdata/clockface'
import {RemoteDataState} from 'src/types'

// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'

interface Props {
onUpdate: (name: string) => void
name: string
onClick?: (e: MouseEvent<HTMLAnchorElement>) => void
placeholder?: string
noNameString: string
parentTestID: string
buttonTestID: string
inputTestID: string
hrefValue: string
}

interface State {
isEditing: boolean
workingName: string
loading: RemoteDataState
}

@ErrorHandling
class ResourceEditableName extends Component<Props, State> {
public static defaultProps = {
parentTestID: 'resource-editable-name',
buttonTestID: 'resource-editable-name--button',
inputTestID: 'resource-editable-name--input',
hrefValue: '#',
}

constructor(props: Props) {
super(props)

this.state = {
isEditing: false,
workingName: props.name,
loading: RemoteDataState.Done,
}
}

public render() {
const {
name,
hrefValue,
noNameString,
parentTestID,
buttonTestID,
} = this.props

return (
<div className={this.className} data-testid={parentTestID}>
<SpinnerContainer
loading={this.state.loading}
spinnerComponent={<TechnoSpinner diameterPixels={20} />}
>
<a href={hrefValue} onClick={this.handleClick}>
<span>{name || noNameString}</span>
</a>
</SpinnerContainer>
<div
className="resource-editable-name--toggle"
onClick={this.handleStartEditing}
data-testid={buttonTestID}
>
<span className="icon pencil" />
</div>
{this.input}
</div>
)
}

private get input(): JSX.Element {
const {placeholder, inputTestID} = this.props
const {workingName, isEditing, loading} = this.state

if (isEditing && loading !== RemoteDataState.Loading) {
return (
<ClickOutside onClickOutside={this.handleStopEditing}>
<Input
size={ComponentSize.ExtraSmall}
maxLength={90}
autoFocus={true}
spellCheck={false}
placeholder={placeholder}
onFocus={this.handleInputFocus}
onChange={this.handleInputChange}
onKeyDown={this.handleKeyDown}
className="resource-editable-name--input"
value={workingName}
testID={inputTestID}
/>
</ClickOutside>
)
}
}

private handleClick = (e: MouseEvent<HTMLAnchorElement>) => {
const {onClick} = this.props
if (onClick) {
onClick(e)
}
}

private handleStartEditing = (): void => {
this.setState({isEditing: true})
}

private handleStopEditing = async (): Promise<void> => {
const {workingName} = this.state
const {onUpdate} = this.props

this.setState({loading: RemoteDataState.Loading})
await onUpdate(workingName)
this.setState({loading: RemoteDataState.Done, isEditing: false})
}

private handleInputChange = (e: ChangeEvent<HTMLInputElement>): void => {
this.setState({workingName: e.target.value})
}

private handleKeyDown = async (
e: KeyboardEvent<HTMLInputElement>
): Promise<void> => {
const {onUpdate, name} = this.props
const {workingName} = this.state

if (e.key === 'Enter') {
e.persist()

if (!workingName) {
this.setState({isEditing: false, workingName: name})

return
}
this.setState({loading: RemoteDataState.Loading})
await onUpdate(workingName)
this.setState({isEditing: false, loading: RemoteDataState.Done})
}

if (e.key === 'Escape') {
this.setState({isEditing: false, workingName: name})
}
}

private handleInputFocus = (e: ChangeEvent<HTMLInputElement>): void => {
e.currentTarget.select()
}

private get className(): string {
const {name, noNameString} = this.props
const {isEditing} = this.state

return classnames('resource-editable-name', {
'resource-editable-name--editing': isEditing,
'untitled-name': name === noNameString,
})
}
}

export default ResourceEditableName
4 changes: 3 additions & 1 deletion ui/src/clockface/components/resource_list/ResourceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import ResourceListHeader from 'src/clockface/components/resource_list/ResourceL
import ResourceListSorter from 'src/clockface/components/resource_list/ResourceListSorter'
import ResourceListBody from 'src/clockface/components/resource_list/ResourceListBody'
import ResourceCard from 'src/clockface/components/resource_list/ResourceCard'
import ResourceName from 'src/clockface/components/resource_list/ResourceName'
import ResourceEditableName from 'src/clockface/components/resource_list/ResourceEditableName'
import ResourceDescription from 'src/clockface/components/resource_list/ResourceDescription'
import ResourceName from 'src/clockface/components/resource_list/ResourceName'

interface Props {
children: JSX.Element[] | JSX.Element
Expand All @@ -19,6 +20,7 @@ export default class ResourceList extends PureComponent<Props> {
public static Body = ResourceListBody
public static Card = ResourceCard
public static Name = ResourceName
public static EditableName = ResourceEditableName
public static Description = ResourceDescription

public render() {
Expand Down
59 changes: 3 additions & 56 deletions ui/src/clockface/components/resource_list/ResourceName.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@
$resource-name-font-size: 17px;
$resource-name-font-weight: 600;

.resource-name > a,
.input.resource-name--input > input {
.resource-editable-name > a {
font-size: $resource-name-font-size;
font-weight: $resource-name-font-weight;
font-family: $ix-text-font;
}

.resource-name > a {
display: inline-block;
white-space: nowrap;
line-height: $form-xs-height;
Expand All @@ -24,54 +20,5 @@ $resource-name-font-weight: 600;
position: relative;
display: inline-flex;
flex-wrap: nowrap;
margin-right: $ix-marg-a;
}

.input.resource-name--input {
position: absolute;
top: 0;
left: 0;
width: 100%;
}

/* Ensure placeholder text matches font weight of title */
.input.resource-name--input > input {
&::-webkit-input-placeholder {
font-weight: $resource-name-font-weight !important;
}
&::-moz-placeholder {
font-weight: $resource-name-font-weight !important;
}
&:-ms-input-placeholder {
font-weight: $resource-name-font-weight !important;
}
&:-moz-placeholder {
font-weight: $resource-name-font-weight !important;
}
}

/* Edit button hover behavior */
.resource-name--toggle {
font-size: $resource-name-font-size * 0.75;
transform: translateY(-10%);
padding: $ix-marg-a;
display: inline-block;
margin-left: $ix-marg-b;
transition: color 0.25s ease, opacity 0.25s ease, width 0.25s ease;
opacity: 0;
width: 0;
color: $g11-sidewalk;

&:hover {
cursor: pointer;
color: $g15-platinum;
}
}

.resource-name:hover,
.resource-name--editing {
.resource-name--toggle {
opacity: 1;
width: $ix-marg-b + $ix-marg-c;
}
}
margin-right: $ix-marg-b;
}
Loading

0 comments on commit 5d99b0b

Please sign in to comment.