mirror of https://github.com/grafana/grafana
parent
e1aff1d5ff
commit
545d7b9477
@ -0,0 +1,78 @@ |
||||
import React from 'react'; |
||||
import { FolderSettings } from './FolderSettings'; |
||||
import { RootStore } from 'app/stores/RootStore/RootStore'; |
||||
import { backendSrv } from 'test/mocks/common'; |
||||
import { shallow } from 'enzyme'; |
||||
|
||||
describe('FolderSettings', () => { |
||||
let wrapper; |
||||
let page; |
||||
|
||||
beforeAll(() => { |
||||
backendSrv.getDashboard.mockReturnValue( |
||||
Promise.resolve({ |
||||
dashboard: { |
||||
id: 1, |
||||
title: 'Folder Name', |
||||
}, |
||||
meta: { |
||||
slug: 'folder-name', |
||||
canSave: true, |
||||
}, |
||||
}) |
||||
); |
||||
|
||||
const store = RootStore.create( |
||||
{}, |
||||
{ |
||||
backendSrv: backendSrv, |
||||
} |
||||
); |
||||
|
||||
wrapper = shallow(<FolderSettings {...store} />); |
||||
return wrapper |
||||
.dive() |
||||
.instance() |
||||
.loadStore() |
||||
.then(() => { |
||||
page = wrapper.dive(); |
||||
}); |
||||
}); |
||||
|
||||
it('should set the title input field', () => { |
||||
const titleInput = page.find('.gf-form-input'); |
||||
expect(titleInput).toHaveLength(1); |
||||
expect(titleInput.prop('value')).toBe('Folder Name'); |
||||
}); |
||||
|
||||
it('should update title and enable save button when changed', () => { |
||||
const titleInput = page.find('.gf-form-input'); |
||||
const disabledSubmitButton = page.find('button[type="submit"]'); |
||||
expect(disabledSubmitButton.prop('disabled')).toBe(true); |
||||
|
||||
titleInput.simulate('change', { target: { value: 'New Title' } }); |
||||
|
||||
const updatedTitleInput = page.find('.gf-form-input'); |
||||
expect(updatedTitleInput.prop('value')).toBe('New Title'); |
||||
const enabledSubmitButton = page.find('button[type="submit"]'); |
||||
expect(enabledSubmitButton.prop('disabled')).toBe(false); |
||||
}); |
||||
|
||||
it('should disable save button if title is changed back to old title', () => { |
||||
const titleInput = page.find('.gf-form-input'); |
||||
|
||||
titleInput.simulate('change', { target: { value: 'Folder Name' } }); |
||||
|
||||
const enabledSubmitButton = page.find('button[type="submit"]'); |
||||
expect(enabledSubmitButton.prop('disabled')).toBe(true); |
||||
}); |
||||
|
||||
it('should disable save button if title is changed to empty string', () => { |
||||
const titleInput = page.find('.gf-form-input'); |
||||
|
||||
titleInput.simulate('change', { target: { value: '' } }); |
||||
|
||||
const enabledSubmitButton = page.find('button[type="submit"]'); |
||||
expect(enabledSubmitButton.prop('disabled')).toBe(true); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,153 @@ |
||||
import React from 'react'; |
||||
import { inject, observer } from 'mobx-react'; |
||||
import { toJS } from 'mobx'; |
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader'; |
||||
import IContainerProps from 'app/containers/IContainerProps'; |
||||
import { getSnapshot } from 'mobx-state-tree'; |
||||
import appEvents from 'app/core/app_events'; |
||||
|
||||
@inject('nav', 'folder', 'view') |
||||
@observer |
||||
export class FolderSettings extends React.Component<IContainerProps, any> { |
||||
formSnapshot: any; |
||||
dashboard: any; |
||||
|
||||
constructor(props) { |
||||
super(props); |
||||
this.loadStore(); |
||||
} |
||||
|
||||
loadStore() { |
||||
const { nav, folder, view } = this.props; |
||||
|
||||
return folder.load(view.routeParams.get('slug') as string).then(res => { |
||||
this.formSnapshot = getSnapshot(folder); |
||||
this.dashboard = res.dashboard; |
||||
|
||||
return nav.initFolderNav(toJS(folder.folder), 'manage-folder-settings'); |
||||
}); |
||||
} |
||||
|
||||
onTitleChange(evt) { |
||||
this.props.folder.setTitle(this.getFormSnapshot().folder.title, evt.target.value); |
||||
} |
||||
|
||||
getFormSnapshot() { |
||||
if (!this.formSnapshot) { |
||||
this.formSnapshot = getSnapshot(this.props.folder); |
||||
} |
||||
|
||||
return this.formSnapshot; |
||||
} |
||||
|
||||
save(evt) { |
||||
if (evt) { |
||||
evt.stopPropagation(); |
||||
evt.preventDefault(); |
||||
} |
||||
|
||||
const { nav, folder, view } = this.props; |
||||
|
||||
folder |
||||
.saveDashboard(this.dashboard, { overwrite: false }) |
||||
.then(newUrl => { |
||||
view.updatePathAndQuery(newUrl, '', ''); |
||||
|
||||
appEvents.emit('dashboard-saved'); |
||||
appEvents.emit('alert-success', ['Folder saved']); |
||||
}) |
||||
.then(() => { |
||||
return nav.initFolderNav(toJS(folder.folder), 'manage-folder-settings'); |
||||
}) |
||||
.catch(this.handleSaveFolderError); |
||||
} |
||||
|
||||
delete(evt) { |
||||
if (evt) { |
||||
evt.stopPropagation(); |
||||
evt.preventDefault(); |
||||
} |
||||
|
||||
const { folder, view } = this.props; |
||||
const title = folder.folder.title; |
||||
|
||||
appEvents.emit('confirm-modal', { |
||||
title: 'Delete', |
||||
text: `Do you want to delete this folder and all its dashboards?`, |
||||
icon: 'fa-trash', |
||||
yesText: 'Delete', |
||||
onConfirm: () => { |
||||
return this.props.folder.deleteFolder().then(() => { |
||||
appEvents.emit('alert-success', ['Folder Deleted', `${title} has been deleted`]); |
||||
view.updatePathAndQuery('dashboards', '', ''); |
||||
}); |
||||
}, |
||||
}); |
||||
} |
||||
|
||||
handleSaveFolderError(err) { |
||||
if (err.data && err.data.status === 'version-mismatch') { |
||||
err.isHandled = true; |
||||
|
||||
appEvents.emit('confirm-modal', { |
||||
title: 'Conflict', |
||||
text: 'Someone else has updated this folder.', |
||||
text2: 'Would you still like to save this folder?', |
||||
yesText: 'Save & Overwrite', |
||||
icon: 'fa-warning', |
||||
onConfirm: () => { |
||||
this.props.folder.saveDashboard(this.dashboard, { overwrite: true }); |
||||
}, |
||||
}); |
||||
} |
||||
|
||||
if (err.data && err.data.status === 'name-exists') { |
||||
err.isHandled = true; |
||||
|
||||
appEvents.emit('alert-error', ['A folder or dashboard with this name exists already.']); |
||||
} |
||||
} |
||||
|
||||
render() { |
||||
const { nav, folder } = this.props; |
||||
|
||||
if (!folder.folder || !nav.main) { |
||||
return <h2>Loading</h2>; |
||||
} |
||||
|
||||
return ( |
||||
<div> |
||||
<PageHeader model={nav as any} /> |
||||
<div className="page-container page-body"> |
||||
<h2 className="page-sub-heading">Folder Settings</h2> |
||||
|
||||
<div className="section gf-form-group"> |
||||
<form name="folderSettingsForm" onSubmit={this.save.bind(this)}> |
||||
<div className="gf-form"> |
||||
<label className="gf-form-label width-7">Name</label> |
||||
<input |
||||
type="text" |
||||
className="gf-form-input width-30" |
||||
value={folder.folder.title} |
||||
onChange={this.onTitleChange.bind(this)} |
||||
/> |
||||
</div> |
||||
<div className="gf-form-button-row"> |
||||
<button |
||||
type="submit" |
||||
className="btn btn-success" |
||||
disabled={!folder.folder.canSave || !folder.folder.hasChanged} |
||||
> |
||||
<i className="fa fa-trash" /> Save |
||||
</button> |
||||
<button className="btn btn-danger" onClick={this.delete.bind(this)} disabled={!folder.folder.canSave}> |
||||
<i className="fa fa-trash" /> Delete |
||||
</button> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
} |
||||
@ -0,0 +1,45 @@ |
||||
import { types, getEnv, flow } from 'mobx-state-tree'; |
||||
|
||||
export const Folder = types.model('Folder', { |
||||
id: types.identifier(types.number), |
||||
slug: types.string, |
||||
title: types.string, |
||||
canSave: types.boolean, |
||||
hasChanged: types.boolean, |
||||
}); |
||||
|
||||
export const FolderStore = types |
||||
.model('FolderStore', { |
||||
folder: types.maybe(Folder), |
||||
}) |
||||
.actions(self => ({ |
||||
load: flow(function* load(slug: string) { |
||||
const backendSrv = getEnv(self).backendSrv; |
||||
const res = yield backendSrv.getDashboard('db', slug); |
||||
self.folder = Folder.create({ |
||||
id: res.dashboard.id, |
||||
title: res.dashboard.title, |
||||
slug: res.meta.slug, |
||||
canSave: res.meta.canSave, |
||||
hasChanged: false, |
||||
}); |
||||
return res; |
||||
}), |
||||
setTitle: function(originalTitle: string, title: string) { |
||||
self.folder.title = title; |
||||
self.folder.hasChanged = originalTitle.toLowerCase() !== title.trim().toLowerCase() && title.trim().length > 0; |
||||
}, |
||||
saveDashboard: flow(function* saveDashboard(dashboard: any, options: any) { |
||||
const backendSrv = getEnv(self).backendSrv; |
||||
dashboard.title = self.folder.title.trim(); |
||||
|
||||
const res = yield backendSrv.saveDashboard(dashboard, options); |
||||
self.folder.slug = res.slug; |
||||
return `dashboards/folder/${self.folder.id}/${res.slug}/settings`; |
||||
}), |
||||
deleteFolder: flow(function* deleteFolder() { |
||||
const backendSrv = getEnv(self).backendSrv; |
||||
|
||||
return backendSrv.deleteDashboard(self.folder.slug); |
||||
}), |
||||
})); |
||||
@ -0,0 +1,47 @@ |
||||
import { NavStore } from './NavStore'; |
||||
|
||||
describe('NavStore', () => { |
||||
const folderId = 1; |
||||
const folderTitle = 'Folder Name'; |
||||
const folderSlug = 'folder-name'; |
||||
const canAdmin = true; |
||||
|
||||
const folder = { |
||||
id: folderId, |
||||
slug: folderSlug, |
||||
title: folderTitle, |
||||
canAdmin: canAdmin, |
||||
}; |
||||
|
||||
let store; |
||||
|
||||
beforeEach(() => { |
||||
store = NavStore.create(); |
||||
store.initFolderNav(folder, 'manage-folder-settings'); |
||||
}); |
||||
|
||||
it('Should set text', () => { |
||||
expect(store.main.text).toBe(folderTitle); |
||||
}); |
||||
|
||||
it('Should load nav with tabs', () => { |
||||
expect(store.main.children.length).toBe(3); |
||||
expect(store.main.children[0].id).toBe('manage-folder-dashboards'); |
||||
expect(store.main.children[1].id).toBe('manage-folder-permissions'); |
||||
expect(store.main.children[2].id).toBe('manage-folder-settings'); |
||||
}); |
||||
|
||||
it('Should set correct urls for each tab', () => { |
||||
expect(store.main.children.length).toBe(3); |
||||
expect(store.main.children[0].url).toBe(`dashboards/folder/${folderId}/${folderSlug}`); |
||||
expect(store.main.children[1].url).toBe(`dashboards/folder/${folderId}/${folderSlug}/permissions`); |
||||
expect(store.main.children[2].url).toBe(`dashboards/folder/${folderId}/${folderSlug}/settings`); |
||||
}); |
||||
|
||||
it('Should set active tab', () => { |
||||
expect(store.main.children.length).toBe(3); |
||||
expect(store.main.children[0].active).toBe(false); |
||||
expect(store.main.children[1].active).toBe(false); |
||||
expect(store.main.children[2].active).toBe(true); |
||||
}); |
||||
}); |
||||
Loading…
Reference in new issue