mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
wip: folder settings page to redux progress
This commit is contained in:
@@ -9,8 +9,8 @@ export const initialState: LocationState = {
|
||||
routeParams: {},
|
||||
};
|
||||
|
||||
function renderUrl(path: string, query: UrlQueryMap): string {
|
||||
if (Object.keys(query).length > 0) {
|
||||
function renderUrl(path: string, query: UrlQueryMap | undefined): string {
|
||||
if (query && Object.keys(query).length > 0) {
|
||||
path += '?' + toUrlParams(query);
|
||||
}
|
||||
return path;
|
||||
|
||||
@@ -252,16 +252,6 @@ export class BackendSrv {
|
||||
return this.post('/api/folders', payload);
|
||||
}
|
||||
|
||||
updateFolder(folder, options) {
|
||||
options = options || {};
|
||||
|
||||
return this.put(`/api/folders/${folder.uid}`, {
|
||||
title: folder.title,
|
||||
version: folder.version,
|
||||
overwrite: options.overwrite === true,
|
||||
});
|
||||
}
|
||||
|
||||
deleteFolder(uid: string, showSuccessAlert) {
|
||||
return this.request({ method: 'DELETE', url: `/api/folders/${uid}`, showSuccessAlert: showSuccessAlert === true });
|
||||
}
|
||||
|
||||
@@ -32,11 +32,9 @@ import './dashlinks/module';
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
import { FolderDashboardsCtrl } from './folder_dashboards_ctrl';
|
||||
import { FolderSettingsCtrl } from './folder_settings_ctrl';
|
||||
import { DashboardImportCtrl } from './dashboard_import_ctrl';
|
||||
import { CreateFolderCtrl } from './create_folder_ctrl';
|
||||
|
||||
coreModule.controller('FolderDashboardsCtrl', FolderDashboardsCtrl);
|
||||
coreModule.controller('FolderSettingsCtrl', FolderSettingsCtrl);
|
||||
coreModule.controller('DashboardImportCtrl', DashboardImportCtrl);
|
||||
coreModule.controller('CreateFolderCtrl', CreateFolderCtrl);
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
import { FolderPageLoader } from './folder_page_loader';
|
||||
import appEvents from 'app/core/app_events';
|
||||
|
||||
export class FolderSettingsCtrl {
|
||||
folderPageLoader: FolderPageLoader;
|
||||
navModel: any;
|
||||
folderId: number;
|
||||
uid: string;
|
||||
canSave = false;
|
||||
folder: any;
|
||||
title: string;
|
||||
hasChanged: boolean;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, navModelSrv, private $routeParams, private $location) {
|
||||
if (this.$routeParams.uid) {
|
||||
this.uid = $routeParams.uid;
|
||||
|
||||
this.folderPageLoader = new FolderPageLoader(this.backendSrv);
|
||||
this.folderPageLoader.load(this, this.uid, 'manage-folder-settings').then(folder => {
|
||||
if ($location.path() !== folder.meta.url) {
|
||||
$location.path(`${folder.meta.url}/settings`).replace();
|
||||
}
|
||||
|
||||
this.folder = folder;
|
||||
this.canSave = this.folder.canSave;
|
||||
this.title = this.folder.title;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
this.titleChanged();
|
||||
|
||||
if (!this.hasChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.folder.title = this.title.trim();
|
||||
|
||||
return this.backendSrv
|
||||
.updateFolder(this.folder)
|
||||
.then(result => {
|
||||
if (result.url !== this.$location.path()) {
|
||||
this.$location.url(result.url + '/settings');
|
||||
}
|
||||
|
||||
appEvents.emit('dashboard-saved');
|
||||
appEvents.emit('alert-success', ['Folder saved']);
|
||||
})
|
||||
.catch(this.handleSaveFolderError);
|
||||
}
|
||||
|
||||
titleChanged() {
|
||||
this.hasChanged = this.folder.title.toLowerCase() !== this.title.trim().toLowerCase();
|
||||
}
|
||||
|
||||
delete(evt) {
|
||||
if (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
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.backendSrv.deleteFolder(this.uid).then(() => {
|
||||
appEvents.emit('alert-success', ['Folder Deleted', `${this.folder.title} has been deleted`]);
|
||||
this.$location.url('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.backendSrv.updateFolder(this.folder, { overwrite: true });
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,121 +4,53 @@ import { connect } from 'react-redux';
|
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { NavModel, StoreState } from 'app/types';
|
||||
import { getFolderByUid } from './state/actions';
|
||||
import { NavModel, StoreState, FolderState } from 'app/types';
|
||||
import { getFolderByUid, setFolderTitle, saveFolder, deleteFolder } from './state/actions';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
folderUid: string;
|
||||
folder: FolderState;
|
||||
getFolderByUid: typeof getFolderByUid;
|
||||
setFolderTitle: typeof setFolderTitle;
|
||||
saveFolder: typeof saveFolder;
|
||||
deleteFolder: typeof deleteFolder;
|
||||
}
|
||||
|
||||
export class FolderSettingsPage extends PureComponent<Props> {
|
||||
// formSnapshot: any;
|
||||
//
|
||||
componentDidMount() {
|
||||
this.props.getFolderByUid(this.props.folderUid);
|
||||
}
|
||||
//
|
||||
// loadStore() {
|
||||
// const { nav, folder, view } = this.props;
|
||||
//
|
||||
// return folder.load(view.routeParams.get('uid') as string).then(res => {
|
||||
// this.formSnapshot = getSnapshot(folder);
|
||||
// view.updatePathAndQuery(`${res.url}/settings`, {}, {});
|
||||
//
|
||||
// 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
|
||||
// .saveFolder({ 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.bind(this));
|
||||
// }
|
||||
//
|
||||
// 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 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;
|
||||
//
|
||||
// const { nav, folder, view } = this.props;
|
||||
//
|
||||
// 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: () => {
|
||||
// folder
|
||||
// .saveFolder({ overwrite: true })
|
||||
// .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');
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
onTitleChange = evt => {
|
||||
this.props.setFolderTitle(evt.target.value);
|
||||
};
|
||||
|
||||
onSave = async evt => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
await this.props.saveFolder(this.props.folder);
|
||||
appEvents.emit('alert-success', ['Folder saved']);
|
||||
};
|
||||
|
||||
onDelete = evt => {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
appEvents.emit('confirm-modal', {
|
||||
title: 'Delete',
|
||||
text: `Do you want to delete this folder and all its dashboards?`,
|
||||
icon: 'fa-trash',
|
||||
yesText: 'Delete',
|
||||
onConfirm: () => {
|
||||
this.props.deleteFolder(this.props.folder.uid);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navModel } = this.props;
|
||||
const { navModel, folder } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -127,25 +59,21 @@ export class FolderSettingsPage extends PureComponent<Props> {
|
||||
<h2 className="page-sub-heading">Folder Settings</h2>
|
||||
|
||||
<div className="section gf-form-group">
|
||||
<form name="folderSettingsForm" onSubmit={this.save.bind(this)}>
|
||||
<form name="folderSettingsForm" onSubmit={this.onSave}>
|
||||
<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)}
|
||||
value={folder.title}
|
||||
onChange={this.onTitleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form-button-row">
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success"
|
||||
disabled={!folder.folder.canSave || !folder.folder.hasChanged}
|
||||
>
|
||||
<button type="submit" className="btn btn-success" disabled={!folder.canSave || !folder.hasChanged}>
|
||||
<i className="fa fa-save" /> Save
|
||||
</button>
|
||||
<button className="btn btn-danger" onClick={this.delete.bind(this)} disabled={!folder.folder.canSave}>
|
||||
<button className="btn btn-danger" onClick={this.onDelete} disabled={!folder.canSave}>
|
||||
<i className="fa fa-trash" /> Delete
|
||||
</button>
|
||||
</div>
|
||||
@@ -159,7 +87,6 @@ export class FolderSettingsPage extends PureComponent<Props> {
|
||||
|
||||
const mapStateToProps = (state: StoreState) => {
|
||||
const uid = state.location.routeParams.uid;
|
||||
|
||||
return {
|
||||
navModel: getNavModel(state.navIndex, `folder-settings-${uid}`),
|
||||
folderUid: uid,
|
||||
@@ -169,6 +96,9 @@ const mapStateToProps = (state: StoreState) => {
|
||||
|
||||
const mapDispatchToProps = {
|
||||
getFolderByUid,
|
||||
saveFolder,
|
||||
setFolderTitle,
|
||||
deleteFolder,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(FolderSettingsPage));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { StoreState } from 'app/types';
|
||||
import { ThunkAction } from 'redux-thunk';
|
||||
import { FolderDTO, NavModelItem } from 'app/types';
|
||||
import { updateNavIndex, UpdateNavIndexAction } from 'app/core/actions';
|
||||
import { FolderDTO, FolderState, NavModelItem } from 'app/types';
|
||||
import { updateNavIndex, updateLocation } from 'app/core/actions';
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadFolder = 'LOAD_FOLDER',
|
||||
@@ -32,7 +32,7 @@ export const setFolderTitle = (newTitle: string): SetFolderTitleAction => ({
|
||||
|
||||
export type Action = LoadFolderAction | SetFolderTitleAction;
|
||||
|
||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action | UpdateNavIndexAction>;
|
||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
|
||||
|
||||
function buildNavModel(folder: FolderDTO): NavModelItem {
|
||||
return {
|
||||
@@ -67,6 +67,7 @@ function buildNavModel(folder: FolderDTO): NavModelItem {
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getFolderByUid(uid: string): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
const folder = await getBackendSrv().getFolderByUid(uid);
|
||||
@@ -74,3 +75,20 @@ export function getFolderByUid(uid: string): ThunkResult<void> {
|
||||
dispatch(updateNavIndex(buildNavModel(folder)));
|
||||
};
|
||||
}
|
||||
|
||||
export function saveFolder(folder: FolderState): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
const res = await getBackendSrv().put(`/api/folders/${folder.uid}`, {
|
||||
title: folder.title,
|
||||
version: folder.version,
|
||||
});
|
||||
dispatch(updateLocation({ path: `${res.url}/settings` }));
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteFolder(uid: string): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
await getBackendSrv().deleteFolder(uid, true);
|
||||
dispatch(updateLocation({ path: `dashboards` }));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@ export const folderReducer = (state = inititalState, action: Action): FolderStat
|
||||
case ActionTypes.LoadFolder:
|
||||
return {
|
||||
...action.payload,
|
||||
canSave: false,
|
||||
hasChanged: false,
|
||||
};
|
||||
case ActionTypes.SetFolderTitle:
|
||||
return {
|
||||
...state,
|
||||
title: action.payload,
|
||||
hasChanged: true,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import { types, getEnv, flow } from 'mobx-state-tree';
|
||||
|
||||
export const Folder = types.model('Folder', {
|
||||
id: types.identifier(types.number),
|
||||
uid: types.string,
|
||||
title: types.string,
|
||||
url: types.string,
|
||||
canSave: types.boolean,
|
||||
hasChanged: types.boolean,
|
||||
version: types.number,
|
||||
});
|
||||
|
||||
export const FolderStore = types
|
||||
.model('FolderStore', {
|
||||
folder: types.maybe(Folder),
|
||||
})
|
||||
.actions(self => ({
|
||||
load: flow(function* load(uid: string) {
|
||||
// clear folder state
|
||||
if (self.folder && self.folder.uid !== uid) {
|
||||
self.folder = null;
|
||||
}
|
||||
|
||||
const backendSrv = getEnv(self).backendSrv;
|
||||
const res = yield backendSrv.getFolderByUid(uid);
|
||||
self.folder = Folder.create({
|
||||
id: res.id,
|
||||
uid: res.uid,
|
||||
title: res.title,
|
||||
url: res.url,
|
||||
canSave: res.canSave,
|
||||
hasChanged: false,
|
||||
version: res.version,
|
||||
});
|
||||
|
||||
return res;
|
||||
}),
|
||||
|
||||
setTitle: (originalTitle: string, title: string) => {
|
||||
self.folder.title = title;
|
||||
self.folder.hasChanged = originalTitle.toLowerCase() !== title.trim().toLowerCase() && title.trim().length > 0;
|
||||
},
|
||||
|
||||
saveFolder: flow(function* saveFolder(options: any) {
|
||||
const backendSrv = getEnv(self).backendSrv;
|
||||
self.folder.title = self.folder.title.trim();
|
||||
|
||||
const res = yield backendSrv.updateFolder(self.folder, options);
|
||||
self.folder.url = res.url;
|
||||
self.folder.version = res.version;
|
||||
|
||||
return `${self.folder.url}/settings`;
|
||||
}),
|
||||
|
||||
deleteFolder: flow(function* deleteFolder() {
|
||||
const backendSrv = getEnv(self).backendSrv;
|
||||
|
||||
return backendSrv.deleteFolder(self.folder.uid);
|
||||
}),
|
||||
}));
|
||||
@@ -4,6 +4,7 @@ export interface FolderDTO {
|
||||
title: string;
|
||||
url: string;
|
||||
version: number;
|
||||
canSave: boolean;
|
||||
}
|
||||
|
||||
export interface FolderState {
|
||||
|
||||
@@ -30,4 +30,5 @@ export interface StoreState {
|
||||
alertRules: AlertRulesState;
|
||||
teams: TeamsState;
|
||||
team: TeamState;
|
||||
folder: FolderState;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user