Folder Permissions
@@ -77,4 +82,17 @@ export class FolderPermissions extends Component
{
}
}
-export default hot(module)(FolderPermissions);
+const mapStateToProps = (state: StoreState) => {
+ const uid = state.location.routeParams.uid;
+ return {
+ navModel: getNavModel(state.navIndex, `folder-permissions-${uid}`, getLoadingNav(1)),
+ folderUid: uid,
+ folder: state.folder,
+ };
+};
+
+const mapDispatchToProps = {
+ getFolderByUid,
+};
+
+export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(FolderPermissions));
diff --git a/public/app/features/folders/FolderSettingsPage.test.tsx b/public/app/features/folders/FolderSettingsPage.test.tsx
new file mode 100644
index 00000000000..3680fa9a197
--- /dev/null
+++ b/public/app/features/folders/FolderSettingsPage.test.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { FolderSettingsPage, Props } from './FolderSettingsPage';
+import { NavModel } from 'app/types';
+import { shallow } from 'enzyme';
+
+const setup = (propOverrides?: object) => {
+ const props: Props = {
+ navModel: {} as NavModel,
+ folderUid: '1234',
+ folder: {
+ id: 0,
+ uid: '1234',
+ title: 'loading',
+ canSave: true,
+ url: 'url',
+ hasChanged: false,
+ version: 1,
+ },
+ getFolderByUid: jest.fn(),
+ setFolderTitle: jest.fn(),
+ saveFolder: jest.fn(),
+ deleteFolder: jest.fn(),
+ };
+
+ Object.assign(props, propOverrides);
+
+ const wrapper = shallow();
+ const instance = wrapper.instance() as FolderSettingsPage;
+
+ return {
+ wrapper,
+ instance,
+ };
+};
+
+describe('Render', () => {
+ it('should render component', () => {
+ const { wrapper } = setup();
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('should enable save button', () => {
+ const { wrapper } = setup({
+ folder: {
+ id: 1,
+ uid: '1234',
+ title: 'loading',
+ canSave: true,
+ hasChanged: true,
+ version: 1,
+ },
+ });
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/app/features/folders/FolderSettingsPage.tsx b/public/app/features/folders/FolderSettingsPage.tsx
new file mode 100644
index 00000000000..1eb7ccafc65
--- /dev/null
+++ b/public/app/features/folders/FolderSettingsPage.tsx
@@ -0,0 +1,105 @@
+import React, { PureComponent } from 'react';
+import { hot } from 'react-hot-loader';
+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, FolderState } from 'app/types';
+import { getFolderByUid, setFolderTitle, saveFolder, deleteFolder } from './state/actions';
+import { getLoadingNav } from './state/navModel';
+
+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 {
+ componentDidMount() {
+ this.props.getFolderByUid(this.props.folderUid);
+ }
+
+ onTitleChange = evt => {
+ this.props.setFolderTitle(evt.target.value);
+ };
+
+ onSave = async evt => {
+ evt.preventDefault();
+ evt.stopPropagation();
+
+ await this.props.saveFolder(this.props.folder);
+ };
+
+ 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, folder } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+const mapStateToProps = (state: StoreState) => {
+ const uid = state.location.routeParams.uid;
+
+ return {
+ navModel: getNavModel(state.navIndex, `folder-settings-${uid}`, getLoadingNav(2)),
+ folderUid: uid,
+ folder: state.folder,
+ };
+};
+
+const mapDispatchToProps = {
+ getFolderByUid,
+ saveFolder,
+ setFolderTitle,
+ deleteFolder,
+};
+
+export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(FolderSettingsPage));
diff --git a/public/app/features/folders/__snapshots__/FolderSettingsPage.test.tsx.snap b/public/app/features/folders/__snapshots__/FolderSettingsPage.test.tsx.snap
new file mode 100644
index 00000000000..2de0c193d27
--- /dev/null
+++ b/public/app/features/folders/__snapshots__/FolderSettingsPage.test.tsx.snap
@@ -0,0 +1,131 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Render should enable save button 1`] = `
+
+
+
+
+ Folder Settings
+
+
+
+
+`;
+
+exports[`Render should render component 1`] = `
+
+
+
+
+ Folder Settings
+
+
+
+
+`;
diff --git a/public/app/features/folders/state/actions.ts b/public/app/features/folders/state/actions.ts
new file mode 100644
index 00000000000..5d153b2fb8a
--- /dev/null
+++ b/public/app/features/folders/state/actions.ts
@@ -0,0 +1,67 @@
+import { getBackendSrv } from 'app/core/services/backend_srv';
+import { StoreState } from 'app/types';
+import { ThunkAction } from 'redux-thunk';
+import { FolderDTO, FolderState } from 'app/types';
+import { updateNavIndex, updateLocation } from 'app/core/actions';
+import { buildNavModel } from './navModel';
+import appEvents from 'app/core/app_events';
+
+export enum ActionTypes {
+ LoadFolder = 'LOAD_FOLDER',
+ SetFolderTitle = 'SET_FOLDER_TITLE',
+ SaveFolder = 'SAVE_FOLDER',
+}
+
+export interface LoadFolderAction {
+ type: ActionTypes.LoadFolder;
+ payload: FolderDTO;
+}
+
+export interface SetFolderTitleAction {
+ type: ActionTypes.SetFolderTitle;
+ payload: string;
+}
+
+export const loadFolder = (folder: FolderDTO): LoadFolderAction => ({
+ type: ActionTypes.LoadFolder,
+ payload: folder,
+});
+
+export const setFolderTitle = (newTitle: string): SetFolderTitleAction => ({
+ type: ActionTypes.SetFolderTitle,
+ payload: newTitle,
+});
+
+export type Action = LoadFolderAction | SetFolderTitleAction;
+
+type ThunkResult = ThunkAction;
+
+
+export function getFolderByUid(uid: string): ThunkResult {
+ return async dispatch => {
+ const folder = await getBackendSrv().getFolderByUid(uid);
+ dispatch(loadFolder(folder));
+ dispatch(updateNavIndex(buildNavModel(folder)));
+ };
+}
+
+export function saveFolder(folder: FolderState): ThunkResult {
+ return async dispatch => {
+ const res = await getBackendSrv().put(`/api/folders/${folder.uid}`, {
+ title: folder.title,
+ version: folder.version,
+ });
+
+ // this should be redux action at some point
+ appEvents.emit('alert-success', ['Folder saved']);
+
+ dispatch(updateLocation({ path: `${res.url}/settings` }));
+ };
+}
+
+export function deleteFolder(uid: string): ThunkResult {
+ return async dispatch => {
+ await getBackendSrv().deleteFolder(uid, true);
+ dispatch(updateLocation({ path: `dashboards` }));
+ };
+}
diff --git a/public/app/features/folders/state/navModel.ts b/public/app/features/folders/state/navModel.ts
new file mode 100644
index 00000000000..e6ef763d019
--- /dev/null
+++ b/public/app/features/folders/state/navModel.ts
@@ -0,0 +1,53 @@
+import { FolderDTO, NavModelItem, NavModel } from 'app/types';
+
+export function buildNavModel(folder: FolderDTO): NavModelItem {
+ return {
+ icon: 'fa fa-folder-open',
+ id: 'manage-folder',
+ subTitle: 'Manage folder dashboards & permissions',
+ url: '',
+ text: folder.title,
+ breadcrumbs: [{ title: 'Dashboards', url: 'dashboards' }],
+ children: [
+ {
+ active: false,
+ icon: 'fa fa-fw fa-th-large',
+ id: `folder-dashboards-${folder.uid}`,
+ text: 'Dashboards',
+ url: folder.url,
+ },
+ {
+ active: false,
+ icon: 'fa fa-fw fa-lock',
+ id: `folder-permissions-${folder.uid}`,
+ text: 'Permissions',
+ url: `${folder.url}/permissions`,
+ },
+ {
+ active: false,
+ icon: 'fa fa-fw fa-cog',
+ id: `folder-settings-${folder.uid}`,
+ text: 'Settings',
+ url: `${folder.url}/settings`,
+ },
+ ],
+ };
+}
+
+export function getLoadingNav(tabIndex: number): NavModel {
+ const main = buildNavModel({
+ id: 1,
+ uid: 'loading',
+ title: 'Loading',
+ url: 'url',
+ canSave: false,
+ version: 0,
+ });
+
+ main.children[tabIndex].active = true;
+
+ return {
+ main: main,
+ node: main.children[tabIndex],
+ };
+}
diff --git a/public/app/features/folders/state/reducers.test.ts b/public/app/features/folders/state/reducers.test.ts
new file mode 100644
index 00000000000..ff37f13f97f
--- /dev/null
+++ b/public/app/features/folders/state/reducers.test.ts
@@ -0,0 +1,42 @@
+import { Action, ActionTypes } from './actions';
+import { FolderDTO } from 'app/types';
+import { inititalState, folderReducer } from './reducers';
+
+function getTestFolder(): FolderDTO {
+ return {
+ id: 1,
+ title: 'test folder',
+ uid: 'asd',
+ url: 'url',
+ canSave: true,
+ version: 0,
+ };
+}
+
+describe('folder reducer', () => {
+ it('should load folder and set hasChanged to false', () => {
+ const folder = getTestFolder();
+
+ const action: Action = {
+ type: ActionTypes.LoadFolder,
+ payload: folder,
+ };
+
+ const state = folderReducer(inititalState, action);
+
+ expect(state.hasChanged).toEqual(false);
+ expect(state.title).toEqual('test folder');
+ });
+
+ it('should set title', () => {
+ const action: Action = {
+ type: ActionTypes.SetFolderTitle,
+ payload: 'new title',
+ };
+
+ const state = folderReducer(inititalState, action);
+
+ expect(state.hasChanged).toEqual(true);
+ expect(state.title).toEqual('new title');
+ });
+});
diff --git a/public/app/features/folders/state/reducers.ts b/public/app/features/folders/state/reducers.ts
new file mode 100644
index 00000000000..41ae10d19e5
--- /dev/null
+++ b/public/app/features/folders/state/reducers.ts
@@ -0,0 +1,33 @@
+import { FolderState } from 'app/types';
+import { Action, ActionTypes } from './actions';
+
+export const inititalState: FolderState = {
+ id: 0,
+ uid: 'loading',
+ title: 'loading',
+ url: '',
+ canSave: false,
+ hasChanged: false,
+ version: 0,
+};
+
+export const folderReducer = (state = inititalState, action: Action): FolderState => {
+ switch (action.type) {
+ case ActionTypes.LoadFolder:
+ return {
+ ...action.payload,
+ hasChanged: false,
+ };
+ case ActionTypes.SetFolderTitle:
+ return {
+ ...state,
+ title: action.payload,
+ hasChanged: action.payload.trim().length > 0,
+ };
+ }
+ return state;
+};
+
+export default {
+ folder: folderReducer,
+};
diff --git a/public/app/features/teams/TeamPages.tsx b/public/app/features/teams/TeamPages.tsx
index f28bde518d2..bbc8b7013ca 100644
--- a/public/app/features/teams/TeamPages.tsx
+++ b/public/app/features/teams/TeamPages.tsx
@@ -7,10 +7,11 @@ import PageHeader from 'app/core/components/PageHeader/PageHeader';
import TeamMembers from './TeamMembers';
import TeamSettings from './TeamSettings';
import TeamGroupSync from './TeamGroupSync';
-import { NavModel, Team } from '../../types';
+import { NavModel, Team } from 'app/types';
import { loadTeam } from './state/actions';
import { getTeam } from './state/selectors';
-import { getNavModel } from '../../core/selectors/navModel';
+import { getTeamLoadingNav } from './state/navModel';
+import { getNavModel } from 'app/core/selectors/navModel';
import { getRouteParamsId, getRouteParamsPage } from '../../core/selectors/location';
export interface Props {
@@ -89,9 +90,10 @@ export class TeamPages extends PureComponent {
function mapStateToProps(state) {
const teamId = getRouteParamsId(state.location);
const pageName = getRouteParamsPage(state.location) || 'members';
+ const teamLoadingNav = getTeamLoadingNav(pageName);
return {
- navModel: getNavModel(state.navIndex, `team-${pageName}-${teamId}`),
+ navModel: getNavModel(state.navIndex, `team-${pageName}-${teamId}`, teamLoadingNav),
teamId: teamId,
pageName: pageName,
team: getTeam(state.team, teamId),
diff --git a/public/app/features/teams/state/actions.ts b/public/app/features/teams/state/actions.ts
index 91aa899e171..d948dc1c5a3 100644
--- a/public/app/features/teams/state/actions.ts
+++ b/public/app/features/teams/state/actions.ts
@@ -1,8 +1,8 @@
import { ThunkAction } from 'redux-thunk';
import { getBackendSrv } from 'app/core/services/backend_srv';
-import { NavModelItem, StoreState, Team, TeamGroup, TeamMember } from 'app/types';
+import { StoreState, Team, TeamGroup, TeamMember } from 'app/types';
import { updateNavIndex, UpdateNavIndexAction } from 'app/core/actions';
-import config from 'app/core/config';
+import { buildNavModel } from './navModel';
export enum ActionTypes {
LoadTeams = 'LOAD_TEAMS',
@@ -90,148 +90,73 @@ export function loadTeams(): ThunkResult {
};
}
-function buildNavModel(team: Team): NavModelItem {
- const navModel = {
- img: team.avatarUrl,
- id: 'team-' + team.id,
- subTitle: 'Manage members & settings',
- url: '',
- text: team.name,
- breadcrumbs: [{ title: 'Teams', url: 'org/teams' }],
- children: [
- {
- active: false,
- icon: 'gicon gicon-team',
- id: `team-members-${team.id}`,
- text: 'Members',
- url: `org/teams/edit/${team.id}/members`,
- },
- {
- active: false,
- icon: 'fa fa-fw fa-sliders',
- id: `team-settings-${team.id}`,
- text: 'Settings',
- url: `org/teams/edit/${team.id}/settings`,
- },
- ],
- };
-
- if (config.buildInfo.isEnterprise) {
- navModel.children.push({
- active: false,
- icon: 'fa fa-fw fa-refresh',
- id: `team-groupsync-${team.id}`,
- text: 'External group sync',
- url: `org/teams/edit/${team.id}/groupsync`,
- });
- }
-
- return navModel;
-}
-
export function loadTeam(id: number): ThunkResult {
return async dispatch => {
- await getBackendSrv()
- .get(`/api/teams/${id}`)
- .then(response => {
- dispatch(teamLoaded(response));
- dispatch(updateNavIndex(buildNavModel(response)));
- });
+ const response = await getBackendSrv().get(`/api/teams/${id}`);
+ dispatch(teamLoaded(response));
+ dispatch(updateNavIndex(buildNavModel(response)));
};
}
export function loadTeamMembers(): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
-
- await getBackendSrv()
- .get(`/api/teams/${team.id}/members`)
- .then(response => {
- dispatch(teamMembersLoaded(response));
- });
+ const response = await getBackendSrv().get(`/api/teams/${team.id}/members`);
+ dispatch(teamMembersLoaded(response));
};
}
export function addTeamMember(id: number): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
-
- await getBackendSrv()
- .post(`/api/teams/${team.id}/members`, { userId: id })
- .then(() => {
- dispatch(loadTeamMembers());
- });
+ await getBackendSrv().post(`/api/teams/${team.id}/members`, { userId: id });
+ dispatch(loadTeamMembers());
};
}
export function removeTeamMember(id: number): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
-
- await getBackendSrv()
- .delete(`/api/teams/${team.id}/members/${id}`)
- .then(() => {
- dispatch(loadTeamMembers());
- });
+ await getBackendSrv().delete(`/api/teams/${team.id}/members/${id}`);
+ dispatch(loadTeamMembers());
};
}
export function updateTeam(name: string, email: string): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
- await getBackendSrv()
- .put(`/api/teams/${team.id}`, {
- name,
- email,
- })
- .then(() => {
- dispatch(loadTeam(team.id));
- });
+ await getBackendSrv().put(`/api/teams/${team.id}`, { name, email });
+ dispatch(loadTeam(team.id));
};
}
export function loadTeamGroups(): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
-
- await getBackendSrv()
- .get(`/api/teams/${team.id}/groups`)
- .then(response => {
- dispatch(teamGroupsLoaded(response));
- });
+ const response = await getBackendSrv().get(`/api/teams/${team.id}/groups`);
+ dispatch(teamGroupsLoaded(response));
};
}
export function addTeamGroup(groupId: string): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
-
- await getBackendSrv()
- .post(`/api/teams/${team.id}/groups`, { groupId: groupId })
- .then(() => {
- dispatch(loadTeamGroups());
- });
+ await getBackendSrv().post(`/api/teams/${team.id}/groups`, { groupId: groupId });
+ dispatch(loadTeamGroups());
};
}
export function removeTeamGroup(groupId: string): ThunkResult {
return async (dispatch, getStore) => {
const team = getStore().team.team;
-
- await getBackendSrv()
- .delete(`/api/teams/${team.id}/groups/${groupId}`)
- .then(() => {
- dispatch(loadTeamGroups());
- });
+ await getBackendSrv().delete(`/api/teams/${team.id}/groups/${groupId}`);
+ dispatch(loadTeamGroups());
};
}
export function deleteTeam(id: number): ThunkResult {
return async dispatch => {
- await getBackendSrv()
- .delete(`/api/teams/${id}`)
- .then(() => {
- dispatch(loadTeams());
- });
+ await getBackendSrv().delete(`/api/teams/${id}`);
+ dispatch(loadTeams());
};
}
diff --git a/public/app/features/teams/state/navModel.ts b/public/app/features/teams/state/navModel.ts
new file mode 100644
index 00000000000..2fd5a68e680
--- /dev/null
+++ b/public/app/features/teams/state/navModel.ts
@@ -0,0 +1,67 @@
+import { Team, NavModelItem, NavModel } from 'app/types';
+import config from 'app/core/config';
+
+export function buildNavModel(team: Team): NavModelItem {
+ const navModel = {
+ img: team.avatarUrl,
+ id: 'team-' + team.id,
+ subTitle: 'Manage members & settings',
+ url: '',
+ text: team.name,
+ breadcrumbs: [{ title: 'Teams', url: 'org/teams' }],
+ children: [
+ {
+ active: false,
+ icon: 'gicon gicon-team',
+ id: `team-members-${team.id}`,
+ text: 'Members',
+ url: `org/teams/edit/${team.id}/members`,
+ },
+ {
+ active: false,
+ icon: 'fa fa-fw fa-sliders',
+ id: `team-settings-${team.id}`,
+ text: 'Settings',
+ url: `org/teams/edit/${team.id}/settings`,
+ },
+ ],
+ };
+
+ if (config.buildInfo.isEnterprise) {
+ navModel.children.push({
+ active: false,
+ icon: 'fa fa-fw fa-refresh',
+ id: `team-groupsync-${team.id}`,
+ text: 'External group sync',
+ url: `org/teams/edit/${team.id}/groupsync`,
+ });
+ }
+
+ return navModel;
+}
+
+export function getTeamLoadingNav(pageName: string): NavModel {
+ const main = buildNavModel({
+ avatarUrl: 'public/img/user_profile.png',
+ id: 1,
+ name: 'Loading',
+ email: 'loading',
+ memberCount: 0,
+ });
+
+ let node: NavModelItem;
+
+ // find active page
+ for (const child of main.children) {
+ if (child.id.indexOf(pageName) > 0) {
+ child.active = true;
+ node = child;
+ break;
+ }
+ }
+
+ return {
+ main: main,
+ node: node,
+ };
+}
diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts
index 519008d70f5..160250dce96 100644
--- a/public/app/routes/routes.ts
+++ b/public/app/routes/routes.ts
@@ -3,10 +3,10 @@ import './ReactContainer';
import ServerStats from 'app/features/admin/ServerStats';
import AlertRuleList from 'app/features/alerting/AlertRuleList';
-import FolderPermissions from 'app/containers/ManageDashboards/FolderPermissions';
import TeamPages from 'app/features/teams/TeamPages';
import TeamList from 'app/features/teams/TeamList';
-import FolderSettings from 'app/containers/ManageDashboards/FolderSettings';
+import FolderSettingsPage from 'app/features/folders/FolderSettingsPage';
+import FolderPermissions from 'app/features/folders/FolderPermissions';
/** @ngInject */
export function setupAngularRoutes($routeProvider, $locationProvider) {
@@ -99,7 +99,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/dashboards/f/:uid/:slug/settings', {
template: '',
resolve: {
- component: () => FolderSettings,
+ component: () => FolderSettingsPage,
},
})
.when('/dashboards/f/:uid/:slug', {
diff --git a/public/app/stores/FolderStore/FolderStore.ts b/public/app/stores/FolderStore/FolderStore.ts
deleted file mode 100644
index 90932cbe46f..00000000000
--- a/public/app/stores/FolderStore/FolderStore.ts
+++ /dev/null
@@ -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);
- }),
- }));
diff --git a/public/app/stores/RootStore/RootStore.ts b/public/app/stores/RootStore/RootStore.ts
index 37c13f48c61..68125fd1f4c 100644
--- a/public/app/stores/RootStore/RootStore.ts
+++ b/public/app/stores/RootStore/RootStore.ts
@@ -1,7 +1,6 @@
import { types } from 'mobx-state-tree';
import { NavStore } from './../NavStore/NavStore';
import { ViewStore } from './../ViewStore/ViewStore';
-import { FolderStore } from './../FolderStore/FolderStore';
import { PermissionsStore } from './../PermissionsStore/PermissionsStore';
export const RootStore = types.model({
@@ -15,7 +14,6 @@ export const RootStore = types.model({
query: {},
routeParams: {},
}),
- folder: types.optional(FolderStore, {}),
});
type RootStoreType = typeof RootStore.Type;
diff --git a/public/app/stores/configureStore.ts b/public/app/stores/configureStore.ts
index 0cdc07fd31a..e06317853f8 100644
--- a/public/app/stores/configureStore.ts
+++ b/public/app/stores/configureStore.ts
@@ -4,11 +4,13 @@ import { createLogger } from 'redux-logger';
import sharedReducers from 'app/core/reducers';
import alertingReducers from 'app/features/alerting/state/reducers';
import teamsReducers from 'app/features/teams/state/reducers';
+import foldersReducers from 'app/features/folders/state/reducers';
const rootReducer = combineReducers({
...sharedReducers,
...alertingReducers,
...teamsReducers,
+ ...foldersReducers,
});
export let store;
diff --git a/public/app/types/folder.ts b/public/app/types/folder.ts
new file mode 100644
index 00000000000..6fbe79cce8c
--- /dev/null
+++ b/public/app/types/folder.ts
@@ -0,0 +1,18 @@
+export interface FolderDTO {
+ id: number;
+ uid: string;
+ title: string;
+ url: string;
+ version: number;
+ canSave: boolean;
+}
+
+export interface FolderState {
+ id: number;
+ uid: string;
+ title: string;
+ url: string;
+ version: number;
+ canSave: boolean;
+ hasChanged: boolean;
+}
diff --git a/public/app/types/index.ts b/public/app/types/index.ts
index 92bcdb32836..52d1ba592c5 100644
--- a/public/app/types/index.ts
+++ b/public/app/types/index.ts
@@ -2,6 +2,7 @@ import { Team, TeamsState, TeamState, TeamGroup, TeamMember } from './teams';
import { AlertRuleDTO, AlertRule, AlertRulesState } from './alerting';
import { LocationState, LocationUpdate, UrlQueryMap, UrlQueryValue } from './location';
import { NavModel, NavModelItem, NavIndex } from './navModel';
+import { FolderDTO, FolderState } from './folder';
export {
Team,
@@ -19,6 +20,8 @@ export {
NavIndex,
UrlQueryMap,
UrlQueryValue,
+ FolderDTO,
+ FolderState,
};
export interface StoreState {
@@ -27,4 +30,5 @@ export interface StoreState {
alertRules: AlertRulesState;
teams: TeamsState;
team: TeamState;
+ folder: FolderState;
}
diff --git a/yarn.lock b/yarn.lock
index fa079d15b72..2b98ff32766 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3182,7 +3182,7 @@ debug@^3.1.0:
dependencies:
ms "^2.1.1"
-debuglog@*, debuglog@^1.0.1:
+debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
@@ -5553,7 +5553,7 @@ import-local@^2.0.0:
pkg-dir "^3.0.0"
resolve-cwd "^2.0.0"
-imurmurhash@*, imurmurhash@^0.1.4:
+imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@@ -6990,10 +6990,6 @@ lodash-es@^4.17.5:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.10.tgz#62cd7104cdf5dd87f235a837f0ede0e8e5117e05"
-lodash._baseindexof@*:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
-
lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
@@ -7001,25 +6997,11 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"
-lodash._bindcallback@*:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
-
-lodash._cacheindexof@*:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
-
-lodash._createcache@*:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
- dependencies:
- lodash._getnative "^3.0.0"
-
lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
-lodash._getnative@*, lodash._getnative@^3.0.0:
+lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
@@ -7103,10 +7085,6 @@ lodash.mergewith@^4.6.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
-lodash.restparam@*:
- version "3.6.1"
- resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
-
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@@ -9902,7 +9880,7 @@ readable-stream@~1.1.10:
isarray "0.0.1"
string_decoder "~0.10.x"
-readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0:
+readdir-scoped-modules@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
dependencies: