Merge pull request #12915 from influxdata/templates/rename-templates-inline

feat(templates): add ability to update template name inline
pull/12930/head
Alirie Gray 2019-03-27 11:32:25 -07:00 committed by GitHub
commit 2b02b3860b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 116 additions and 18 deletions

View File

@ -30,6 +30,7 @@
1. [12782](https://github.com/influxdata/influxdb/pull/12782): Move bucket selection in the query builder to the first card in the list
1. [12850](https://github.com/influxdata/influxdb/pull/12850): Ensure editor is automatically focused in note editor
1. [12915](https://github.com/influxdata/influxdb/pull/12915): Add ability to edit a template's name.
## v2.0.0-alpha.6 [2019-03-15]

22
ui/package-lock.json generated
View File

@ -985,9 +985,9 @@
}
},
"@influxdata/influx": {
"version": "0.2.52",
"resolved": "https://registry.npmjs.org/@influxdata/influx/-/influx-0.2.52.tgz",
"integrity": "sha512-EK1JR2c7pHqJVmWF8KcBVqdoM9MUn/tK+GeRUC2WLuI+HK7dAuc8oVvnDb1dXh01VQq3oQQxwSNO40tm9Opgrw==",
"version": "0.2.53",
"resolved": "https://registry.npmjs.org/@influxdata/influx/-/influx-0.2.53.tgz",
"integrity": "sha512-xOTUkDMyjT5G1yKLWt2U7FFhlmABStZtdAuMnq49CnsXxPokrWmVFcfZ0vtXTtlQLK6cdjpE/UY/N5MACBjYmQ==",
"requires": {
"axios": "^0.18.0"
}
@ -2544,7 +2544,7 @@
},
"bindings": {
"version": "1.2.1",
"resolved": "http://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
"integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=",
"dev": true
},
@ -2962,7 +2962,7 @@
},
"callsites": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
"dev": true
},
@ -3756,7 +3756,7 @@
},
"css-color-names": {
"version": "0.0.4",
"resolved": "http://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
"integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
"dev": true
},
@ -4638,7 +4638,7 @@
},
"dotenv": {
"version": "5.0.1",
"resolved": "http://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
"integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==",
"dev": true
},
@ -8277,7 +8277,7 @@
},
"is-obj": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"dev": true
},
@ -10076,7 +10076,7 @@
},
"magic-string": {
"version": "0.22.5",
"resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
"integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
"dev": true,
"requires": {
@ -11031,7 +11031,7 @@
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
},
@ -11458,7 +11458,7 @@
},
"json5": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {

View File

@ -137,7 +137,7 @@
},
"dependencies": {
"@influxdata/clockface": "0.0.8",
"@influxdata/influx": "0.2.52",
"@influxdata/influx": "0.2.53",
"@influxdata/react-custom-scrollbars": "4.3.8",
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",

View File

@ -845,6 +845,16 @@ export const createTemplateFailed = (error: string): Notification => ({
message: `Failed to export resource as template: ${error}`,
})
export const updateTemplateSucceeded = (): Notification => ({
...defaultSuccessNotification,
message: `Successfully updated template.`,
})
export const updateTemplateFailed = (error: string): Notification => ({
...defaultErrorNotification,
message: `Failed to update template: ${error}`,
})
export const deleteTemplateFailed = (error: string): Notification => ({
...defaultErrorNotification,
message: `Failed to delete template: ${error}`,

View File

@ -23,6 +23,7 @@ export enum ActionTypes {
SetExportTemplate = 'SET_EXPORT_TEMPLATE',
RemoveTemplateSummary = 'REMOVE_TEMPLATE_SUMMARY',
AddTemplateSummary = 'ADD_TEMPLATE_SUMMARY',
SetTemplateSummary = 'SET_TEMPLATE_SUMMARY',
}
export type Actions =
@ -31,6 +32,7 @@ export type Actions =
| SetExportTemplate
| RemoveTemplateSummary
| AddTemplateSummary
| SetTemplateSummary
export interface AddTemplateSummary {
type: ActionTypes.AddTemplateSummary
@ -108,6 +110,33 @@ export const createTemplate = (template: DocumentCreate) => async dispatch => {
}
}
interface SetTemplateSummary {
type: ActionTypes.SetTemplateSummary
payload: {id: string; templateSummary: TemplateSummary}
}
export const setTemplateSummary = (
id: string,
templateSummary: TemplateSummary
): SetTemplateSummary => ({
type: ActionTypes.SetTemplateSummary,
payload: {id, templateSummary},
})
export const updateTemplate = (id: string, props: TemplateSummary) => async (
dispatch
): Promise<void> => {
try {
const {meta} = await client.templates.update(id, props)
dispatch(setTemplateSummary(id, {...props, meta}))
dispatch(notify(copy.updateTemplateSucceeded()))
} catch (e) {
console.error(e)
dispatch(notify(copy.updateTemplateFailed(e)))
}
}
export const convertToTemplate = (id: string) => async (
dispatch
): Promise<void> => {

View File

@ -7,7 +7,11 @@ import {withRouter, WithRouterProps} from 'react-router'
import {ResourceList, Context, IconFont} from 'src/clockface'
// Actions
import {deleteTemplate, cloneTemplate} from 'src/templates/actions'
import {
deleteTemplate,
cloneTemplate,
updateTemplate,
} from 'src/templates/actions'
// Types
import {TemplateSummary} from '@influxdata/influx'
@ -24,6 +28,7 @@ interface OwnProps {
interface DispatchProps {
onDelete: typeof deleteTemplate
onClone: typeof cloneTemplate
onUpdate: typeof updateTemplate
}
type Props = DispatchProps & OwnProps
@ -39,7 +44,7 @@ export class TemplateCard extends PureComponent<Props & WithRouterProps> {
name={() => (
<ResourceList.Name
onClick={this.handleNameClick}
onUpdate={this.doNothing}
onUpdate={this.handleUpdateTemplate}
name={template.meta.name}
noNameString={DEFAULT_TEMPLATE_NAME}
parentTestID="template-card--name"
@ -51,8 +56,14 @@ export class TemplateCard extends PureComponent<Props & WithRouterProps> {
)
}
//TODO handle rename template
private doNothing = () => {}
private handleUpdateTemplate = (name: string) => {
const {template} = this.props
this.props.onUpdate(template.id, {
...template,
meta: {...template.meta, name},
})
}
private get contextMenu(): JSX.Element {
const {
@ -110,6 +121,7 @@ export class TemplateCard extends PureComponent<Props & WithRouterProps> {
const mdtp: DispatchProps = {
onDelete: deleteTemplate,
onClone: cloneTemplate,
onUpdate: updateTemplate,
}
export default connect<{}, DispatchProps, OwnProps>(

View File

@ -0,0 +1,36 @@
import templatesReducer, {defaultState} from 'src/templates/reducers'
import {setTemplateSummary} from 'src/templates/actions'
describe('templatesReducer', () => {
describe('setTemplateSummary', () => {
it('can update the name of a template', () => {
const initialState = defaultState()
const initialTemplate = {
id: 'abc',
labels: [],
meta: {name: 'Belcalis', version: '1'},
}
initialState.items.push(initialTemplate)
const actual = templatesReducer(
initialState,
setTemplateSummary(initialTemplate.id, {
...initialTemplate,
meta: {...initialTemplate.meta, name: 'Cardi B'},
})
)
const expected = {
...defaultState(),
items: [
{
...initialTemplate,
meta: {...initialTemplate.meta, name: 'Cardi B'},
},
],
}
expect(actual).toEqual(expected)
})
})
})

View File

@ -9,7 +9,7 @@ export interface TemplatesState {
exportTemplate: {status: RemoteDataState; item: DocumentCreate; orgID: string}
}
const defaultState = (): TemplatesState => ({
export const defaultState = (): TemplatesState => ({
status: RemoteDataState.NotStarted,
items: [],
exportTemplate: {
@ -19,7 +19,7 @@ const defaultState = (): TemplatesState => ({
},
})
const templatesReducer = (
export const templatesReducer = (
state: TemplatesState = defaultState(),
action: Actions
): TemplatesState =>
@ -42,6 +42,16 @@ const templatesReducer = (
return
}
case ActionTypes.SetTemplateSummary: {
const filtered = draftState.items.filter(t => {
return t.id !== action.payload.id
})
draftState.items = [...filtered, action.payload.templateSummary]
return
}
case ActionTypes.SetExportTemplate: {
const {status, item, orgID} = action.payload
draftState.exportTemplate.status = status