Просмотр исходного кода

wip: folder settings page to redux progress

Torkel Ödegaard 7 лет назад
Родитель
Сommit
19cbff658b

+ 2 - 2
public/app/core/reducers/location.ts

@@ -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;

+ 0 - 10
public/app/core/services/backend_srv.ts

@@ -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 });
   }

+ 0 - 2
public/app/features/dashboard/all.ts

@@ -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);

+ 0 - 94
public/app/features/dashboard/folder_settings_ctrl.ts

@@ -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 });
-        },
-      });
-    }
-  }
-}

+ 41 - 111
public/app/features/manage-dashboards/FolderSettingsPage.tsx

@@ -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));

+ 21 - 3
public/app/features/manage-dashboards/state/actions.ts

@@ -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` }));
+  };
+}

+ 6 - 1
public/app/features/manage-dashboards/state/reducers.ts

@@ -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;
 };

+ 0 - 60
public/app/stores/FolderStore/FolderStore.ts

@@ -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);
-    }),
-  }));

+ 1 - 0
public/app/types/dashboard.ts

@@ -4,6 +4,7 @@ export interface FolderDTO {
   title: string;
   url: string;
   version: number;
+  canSave: boolean;
 }
 
 export interface FolderState {

+ 1 - 0
public/app/types/index.ts

@@ -30,4 +30,5 @@ export interface StoreState {
   alertRules: AlertRulesState;
   teams: TeamsState;
   team: TeamState;
+  folder: FolderState;
 }