From 358b065f0c1a8dab9580e17ab33e0f737504f480 Mon Sep 17 00:00:00 2001 From: Alirie Gray Date: Tue, 26 Mar 2019 14:16:38 -0700 Subject: [PATCH] feat(templates): add ability to update template name inline --- CHANGELOG.md | 1 + ui/package-lock.json | 22 ++++++------ ui/package.json | 2 +- ui/src/shared/copy/notifications.ts | 10 ++++++ ui/src/templates/actions/index.ts | 29 ++++++++++++++++ ui/src/templates/components/TemplateCard.tsx | 20 ++++++++--- ui/src/templates/reducers/index.test.ts | 36 ++++++++++++++++++++ ui/src/templates/reducers/index.ts | 14 ++++++-- 8 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 ui/src/templates/reducers/index.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index bb8302fc97c..2df59a68b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] diff --git a/ui/package-lock.json b/ui/package-lock.json index 4dc6d88c2cc..c8db54f49ea 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -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": { diff --git a/ui/package.json b/ui/package.json index 4a9a24b6092..f622e41f28a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -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", diff --git a/ui/src/shared/copy/notifications.ts b/ui/src/shared/copy/notifications.ts index 4373628a16d..79e92b7dbcd 100644 --- a/ui/src/shared/copy/notifications.ts +++ b/ui/src/shared/copy/notifications.ts @@ -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}`, diff --git a/ui/src/templates/actions/index.ts b/ui/src/templates/actions/index.ts index c283ae5f1d1..c20bb293e92 100644 --- a/ui/src/templates/actions/index.ts +++ b/ui/src/templates/actions/index.ts @@ -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 => { + 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 => { diff --git a/ui/src/templates/components/TemplateCard.tsx b/ui/src/templates/components/TemplateCard.tsx index 57bd52dd5a6..cda49e4216e 100644 --- a/ui/src/templates/components/TemplateCard.tsx +++ b/ui/src/templates/components/TemplateCard.tsx @@ -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 { name={() => ( { ) } - //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 { const mdtp: DispatchProps = { onDelete: deleteTemplate, onClone: cloneTemplate, + onUpdate: updateTemplate, } export default connect<{}, DispatchProps, OwnProps>( diff --git a/ui/src/templates/reducers/index.test.ts b/ui/src/templates/reducers/index.test.ts new file mode 100644 index 00000000000..b9f1012de89 --- /dev/null +++ b/ui/src/templates/reducers/index.test.ts @@ -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) + }) + }) +}) diff --git a/ui/src/templates/reducers/index.ts b/ui/src/templates/reducers/index.ts index d55e690213d..8e46d87e64e 100644 --- a/ui/src/templates/reducers/index.ts +++ b/ui/src/templates/reducers/index.ts @@ -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