Peter Holmberg 7 anni fa
parent
commit
037e9ad0bd

+ 29 - 0
public/app/features/datasources/AddDataSourcePermissions.test.tsx

@@ -0,0 +1,29 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { AddDataSourcePermissions, Props } from './AddDataSourcePermissions';
+import { AclTarget } from '../../types/acl';
+
+const setup = () => {
+  const props: Props = {
+    onAddPermission: jest.fn(),
+    onCancel: jest.fn(),
+  };
+
+  return shallow(<AddDataSourcePermissions {...props} />);
+};
+
+describe('Render', () => {
+  it('should render component', () => {
+    const wrapper = setup();
+
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  it('should render user picker', () => {
+    const wrapper = setup();
+
+    wrapper.instance().setState({ type: AclTarget.User });
+
+    expect(wrapper).toMatchSnapshot();
+  });
+});

+ 77 - 0
public/app/features/datasources/DataSourcePermissions.test.tsx

@@ -0,0 +1,77 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { DataSourcePermissions, Props } from './DataSourcePermissions';
+import { DataSourcePermission, DataSourcePermissionDTO } from 'app/types';
+import { AclTarget, dashboardPermissionLevels } from '../../types/acl';
+
+const setup = (propOverrides?: object) => {
+  const props: Props = {
+    dataSourcePermission: {} as DataSourcePermissionDTO,
+    pageId: 1,
+    addDataSourcePermission: jest.fn(),
+    enableDataSourcePermissions: jest.fn(),
+    disableDataSourcePermissions: jest.fn(),
+    loadDataSourcePermissions: jest.fn(),
+    removeDataSourcePermission: jest.fn(),
+  };
+
+  Object.assign(props, propOverrides);
+
+  const wrapper = shallow(<DataSourcePermissions {...props} />);
+  const instance = wrapper.instance() as DataSourcePermissions;
+
+  return {
+    wrapper,
+    instance,
+  };
+};
+
+describe('Render', () => {
+  it('should render component', () => {
+    const { wrapper } = setup();
+
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  it('should render permissions enabled', () => {
+    const { wrapper } = setup({
+      dataSourcePermission: {
+        enabled: true,
+        datasourceId: 1,
+        permissions: [] as DataSourcePermission[],
+      },
+    });
+
+    expect(wrapper).toMatchSnapshot();
+  });
+});
+
+describe('Functions', () => {
+  describe('on add permissions', () => {
+    const { instance } = setup();
+
+    it('should add permissions for team', () => {
+      const mockState = {
+        permission: dashboardPermissionLevels[0].value,
+        teamId: 1,
+        type: AclTarget.Team,
+      };
+
+      instance.onAddPermission(mockState);
+
+      expect(instance.props.addDataSourcePermission).toHaveBeenCalledWith(1, { teamId: 1, permission: 1 });
+    });
+
+    it('should add permissions for user', () => {
+      const mockState = {
+        permission: dashboardPermissionLevels[0].value,
+        userId: 1,
+        type: AclTarget.User,
+      };
+
+      instance.onAddPermission(mockState);
+
+      expect(instance.props.addDataSourcePermission).toHaveBeenCalledWith(1, { userId: 1, permission: 1 });
+    });
+  });
+});

+ 4 - 8
public/app/features/datasources/DataSourcePermissions.tsx

@@ -11,11 +11,11 @@ import {
   loadDataSourcePermissions,
   removeDataSourcePermission,
 } from './state/actions';
-import { DataSourcePermission } from 'app/types';
+import { DataSourcePermissionDTO } from 'app/types';
 import { getRouteParamsId } from '../../core/selectors/location';
 
 export interface Props {
-  dataSourcePermission: { enabled: boolean; datasouceId: number; permissions: DataSourcePermission[] };
+  dataSourcePermission: DataSourcePermissionDTO;
   pageId: number;
   addDataSourcePermission: typeof addDataSourcePermission;
   enableDataSourcePermissions: typeof enableDataSourcePermissions;
@@ -64,17 +64,13 @@ export class DataSourcePermissions extends PureComponent<Props, State> {
     const { pageId, addDataSourcePermission } = this.props;
     const data = {
       permission: state.permission,
-      userId: 0,
-      teamId: 0,
     };
 
     if (state.type === AclTarget.Team) {
-      data.teamId = state.teamId;
+      addDataSourcePermission(pageId, Object.assign(data, { teamId: state.teamId }));
     } else if (state.type === AclTarget.User) {
-      data.userId = state.userId;
+      addDataSourcePermission(pageId, Object.assign(data, { userId: state.userId }));
     }
-
-    addDataSourcePermission(pageId, data);
   };
 
   onRemovePermission = item => {

+ 32 - 0
public/app/features/datasources/DataSourcePermissionsList.test.tsx

@@ -0,0 +1,32 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { DataSourcePermissionsList, Props } from './DataSourcePermissionsList';
+import { DataSourcePermission } from '../../types';
+import { getMockDataSourcePermissionsTeam, getMockDataSourcePermissionsUser } from './__mocks__/dataSourcesMocks';
+
+const setup = (propOverrides?: object) => {
+  const props: Props = {
+    items: [] as DataSourcePermission[],
+    onRemoveItem: jest.fn(),
+  };
+
+  Object.assign(props, propOverrides);
+
+  return shallow(<DataSourcePermissionsList {...props} />);
+};
+
+describe('Render', () => {
+  it('should render component', () => {
+    const wrapper = setup();
+
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  it('should render items', () => {
+    const wrapper = setup({
+      items: [getMockDataSourcePermissionsUser(), getMockDataSourcePermissionsTeam()],
+    });
+
+    expect(wrapper).toMatchSnapshot();
+  });
+});

+ 1 - 1
public/app/features/datasources/DataSourcePermissionsList.tsx

@@ -3,7 +3,7 @@ import { DataSourcePermission } from '../../types';
 import { dataSourceAclLevels, DataSourcePermissionLevel } from '../../types/acl';
 import DescriptionPicker from '../../core/components/Picker/DescriptionPicker';
 
-interface Props {
+export interface Props {
   items: DataSourcePermission[];
   onRemoveItem: (item) => void;
 }

+ 30 - 1
public/app/features/datasources/__mocks__/dataSourcesMocks.ts

@@ -1,4 +1,4 @@
-import { DataSource } from 'app/types';
+import { DataSource, DataSourcePermission } from 'app/types';
 
 export const getMockDataSources = (amount: number): DataSource[] => {
   const dataSources = [];
@@ -43,3 +43,32 @@ export const getMockDataSource = (): DataSource => {
     user: '',
   };
 };
+
+export const getMockDataSourcePermissionsUser = (): DataSourcePermission => {
+  return {
+    created: '2018-10-10T16:50:45+02:00',
+    datasourceId: 1,
+    id: 2,
+    permission: 1,
+    permissionName: 'Query',
+    updated: '2018-10-10T16:50:45+02:00',
+    userAvatarUrl: '/avatar/926aa85c6bcefa0b4deca3223f337ae1',
+    userEmail: 'test@test.com',
+    userId: 3,
+    userLogin: 'testUser',
+  };
+};
+
+export const getMockDataSourcePermissionsTeam = (): DataSourcePermission => {
+  return {
+    created: '2018-10-10T16:57:09+02:00',
+    datasourceId: 1,
+    id: 6,
+    permission: 1,
+    permissionName: 'Query',
+    team: 'A-team',
+    teamAvatarUrl: '/avatar/93c0801b955cbd443a8cfa91a401d7bc',
+    teamId: 1,
+    updated: '2018-10-10T16:57:09+02:00',
+  };
+};

+ 179 - 0
public/app/features/datasources/__snapshots__/AddDataSourcePermissions.test.tsx.snap

@@ -0,0 +1,179 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Render should render component 1`] = `
+<div
+  className="gf-form-inline cta-form"
+>
+  <button
+    className="cta-form__close btn btn-transparent"
+    onClick={[MockFunction]}
+  >
+    <i
+      className="fa fa-close"
+    />
+  </button>
+  <form
+    name="addPermission"
+    onSubmit={[Function]}
+  >
+    <h5>
+      Add Permission For
+    </h5>
+    <div
+      className="gf-form-inline"
+    >
+      <div
+        className="gf-form"
+      >
+        <select
+          className="gf-form-input gf-size-auto"
+          onChange={[Function]}
+          value="Team"
+        >
+          <option
+            key="0"
+            value="Team"
+          >
+            Team
+          </option>
+          <option
+            key="1"
+            value="User"
+          >
+            User
+          </option>
+        </select>
+      </div>
+      <div
+        className="gf-form"
+      >
+        <TeamPicker
+          className="width-20"
+          onSelected={[Function]}
+          value="0"
+        />
+      </div>
+      <div
+        className="gf-form"
+      >
+        <DescriptionPicker
+          className="gf-form-input--form-dropdown-right"
+          disabled={false}
+          onSelected={[Function]}
+          optionsWithDesc={
+            Array [
+              Object {
+                "description": "Can query data source.",
+                "label": "Query",
+                "value": 1,
+              },
+            ]
+          }
+          value={1}
+        />
+      </div>
+      <div
+        className="gf-form"
+      >
+        <button
+          className="btn btn-success"
+          data-save-permission={true}
+          disabled={true}
+          type="submit"
+        >
+          Save
+        </button>
+      </div>
+    </div>
+  </form>
+</div>
+`;
+
+exports[`Render should render user picker 1`] = `
+<div
+  className="gf-form-inline cta-form"
+>
+  <button
+    className="cta-form__close btn btn-transparent"
+    onClick={[MockFunction]}
+  >
+    <i
+      className="fa fa-close"
+    />
+  </button>
+  <form
+    name="addPermission"
+    onSubmit={[Function]}
+  >
+    <h5>
+      Add Permission For
+    </h5>
+    <div
+      className="gf-form-inline"
+    >
+      <div
+        className="gf-form"
+      >
+        <select
+          className="gf-form-input gf-size-auto"
+          onChange={[Function]}
+          value="User"
+        >
+          <option
+            key="0"
+            value="Team"
+          >
+            Team
+          </option>
+          <option
+            key="1"
+            value="User"
+          >
+            User
+          </option>
+        </select>
+      </div>
+      <div
+        className="gf-form"
+      >
+        <UserPicker
+          className="width-20"
+          onSelected={[Function]}
+          value="0"
+        />
+      </div>
+      <div
+        className="gf-form"
+      >
+        <DescriptionPicker
+          className="gf-form-input--form-dropdown-right"
+          disabled={false}
+          onSelected={[Function]}
+          optionsWithDesc={
+            Array [
+              Object {
+                "description": "Can query data source.",
+                "label": "Query",
+                "value": 1,
+              },
+            ]
+          }
+          value={1}
+        />
+      </div>
+      <div
+        className="gf-form"
+      >
+        <button
+          className="btn btn-success"
+          data-save-permission={true}
+          disabled={true}
+          type="submit"
+        >
+          Save
+        </button>
+      </div>
+    </div>
+  </form>
+</div>
+`;

+ 92 - 0
public/app/features/datasources/__snapshots__/DataSourcePermissions.test.tsx.snap

@@ -0,0 +1,92 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Render should render component 1`] = `
+<div>
+  <div
+    className="page-action-bar"
+  >
+    <h3
+      className="page-sub-heading"
+    >
+      Permissions
+    </h3>
+    <div
+      className="page-action-bar__spacer"
+    />
+  </div>
+  <div
+    className="empty-list-cta"
+  >
+    <div
+      className="empty-list-cta__title"
+    >
+      Permissions not enabled for this data source.
+    </div>
+    <button
+      className="empty-list-cta__button btn btn-xlarge btn-success"
+      onClick={[Function]}
+    >
+      Enable
+    </button>
+    <div
+      className="empty-list-cta__pro-tip"
+    >
+      <i
+        className="fa fa-rocket"
+      />
+       ProTip:
+       
+      Only admins will be able to query the data source after you enable permissions.
+    </div>
+  </div>
+</div>
+`;
+
+exports[`Render should render permissions enabled 1`] = `
+<div>
+  <div
+    className="page-action-bar"
+  >
+    <h3
+      className="page-sub-heading"
+    >
+      Permissions
+    </h3>
+    <div
+      className="page-action-bar__spacer"
+    />
+    <button
+      className="btn btn-success pull-right"
+      disabled={false}
+      key="add-permission"
+      onClick={[Function]}
+    >
+      <i
+        className="fa fa-plus"
+      />
+       Add Permission
+    </button>
+    <button
+      className="btn btn-danger pull-right"
+      key="disable-permissions"
+      onClick={[Function]}
+    >
+      Disable Permissions
+    </button>
+  </div>
+  <div>
+    <Component
+      in={false}
+    >
+      <AddDataSourcePermissions
+        onAddPermission={[Function]}
+        onCancel={[Function]}
+      />
+    </Component>
+    <DataSourcePermissionsList
+      items={Array []}
+      onRemoveItem={[Function]}
+    />
+  </div>
+</div>
+`;

+ 342 - 0
public/app/features/datasources/__snapshots__/DataSourcePermissionsList.test.tsx.snap

@@ -0,0 +1,342 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Render should render component 1`] = `
+<table
+  className="filter-table gf-form-group"
+>
+  <tbody>
+    <tr
+      className="gf-form-disabled"
+    >
+      <td
+        style={
+          Object {
+            "width": "1%",
+          }
+        }
+      >
+        <i
+          className="gicon gicon-shield"
+          style={
+            Object {
+              "height": "25px",
+              "width": "25px",
+            }
+          }
+        />
+      </td>
+      <td
+        style={
+          Object {
+            "width": "90%",
+          }
+        }
+      >
+        Admin
+        <span
+          className="filter-table__weak-italic"
+        >
+           (Role)
+        </span>
+      </td>
+      <td />
+      <td
+        className="query-keyword"
+      >
+        Can
+      </td>
+      <td>
+        <div
+          className="gf-form"
+        >
+          <DescriptionPicker
+            className="gf-form-input--form-dropdown-right"
+            disabled={true}
+            onSelected={[Function]}
+            optionsWithDesc={
+              Array [
+                Object {
+                  "description": "Can query data source.",
+                  "label": "Query",
+                  "value": 1,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+              ]
+            }
+            value={2}
+          />
+        </div>
+      </td>
+      <td>
+        <button
+          className="btn btn-inverse btn-small"
+        >
+          <i
+            className="fa fa-lock"
+          />
+        </button>
+      </td>
+    </tr>
+  </tbody>
+</table>
+`;
+
+exports[`Render should render items 1`] = `
+<table
+  className="filter-table gf-form-group"
+>
+  <tbody>
+    <tr
+      className="gf-form-disabled"
+    >
+      <td
+        style={
+          Object {
+            "width": "1%",
+          }
+        }
+      >
+        <i
+          className="gicon gicon-shield"
+          style={
+            Object {
+              "height": "25px",
+              "width": "25px",
+            }
+          }
+        />
+      </td>
+      <td
+        style={
+          Object {
+            "width": "90%",
+          }
+        }
+      >
+        Admin
+        <span
+          className="filter-table__weak-italic"
+        >
+           (Role)
+        </span>
+      </td>
+      <td />
+      <td
+        className="query-keyword"
+      >
+        Can
+      </td>
+      <td>
+        <div
+          className="gf-form"
+        >
+          <DescriptionPicker
+            className="gf-form-input--form-dropdown-right"
+            disabled={true}
+            onSelected={[Function]}
+            optionsWithDesc={
+              Array [
+                Object {
+                  "description": "Can query data source.",
+                  "label": "Query",
+                  "value": 1,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+              ]
+            }
+            value={2}
+          />
+        </div>
+      </td>
+      <td>
+        <button
+          className="btn btn-inverse btn-small"
+        >
+          <i
+            className="fa fa-lock"
+          />
+        </button>
+      </td>
+    </tr>
+    <tr
+      key="2-0"
+    >
+      <td
+        style={
+          Object {
+            "width": "1%",
+          }
+        }
+      >
+        <img
+          className="filter-table__avatar"
+          src="/avatar/926aa85c6bcefa0b4deca3223f337ae1"
+        />
+      </td>
+      <td
+        style={
+          Object {
+            "width": "90%",
+          }
+        }
+      >
+        <span
+          key="name"
+        >
+          testUser
+           
+        </span>
+        <span
+          className="filter-table__weak-italic"
+          key="description"
+        >
+          (User)
+        </span>
+      </td>
+      <td />
+      <td
+        className="query-keyword"
+      >
+        Can
+      </td>
+      <td>
+        <div
+          className="gf-form"
+        >
+          <DescriptionPicker
+            className="gf-form-input--form-dropdown-right"
+            disabled={true}
+            onSelected={[Function]}
+            optionsWithDesc={
+              Array [
+                Object {
+                  "description": "Can query data source.",
+                  "label": "Query",
+                  "value": 1,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+              ]
+            }
+            value={1}
+          />
+        </div>
+      </td>
+      <td>
+        <button
+          className="btn btn-danger btn-small"
+          onClick={[Function]}
+        >
+          <i
+            className="fa fa-remove"
+          />
+        </button>
+      </td>
+    </tr>
+    <tr
+      key="6-1"
+    >
+      <td
+        style={
+          Object {
+            "width": "1%",
+          }
+        }
+      >
+        <img
+          className="filter-table__avatar"
+          src="/avatar/93c0801b955cbd443a8cfa91a401d7bc"
+        />
+      </td>
+      <td
+        style={
+          Object {
+            "width": "90%",
+          }
+        }
+      >
+        <span
+          key="name"
+        >
+          A-team
+           
+        </span>
+        <span
+          className="filter-table__weak-italic"
+          key="description"
+        >
+          (Team)
+        </span>
+      </td>
+      <td />
+      <td
+        className="query-keyword"
+      >
+        Can
+      </td>
+      <td>
+        <div
+          className="gf-form"
+        >
+          <DescriptionPicker
+            className="gf-form-input--form-dropdown-right"
+            disabled={true}
+            onSelected={[Function]}
+            optionsWithDesc={
+              Array [
+                Object {
+                  "description": "Can query data source.",
+                  "label": "Query",
+                  "value": 1,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+                Object {
+                  "description": "",
+                  "label": "Admin",
+                  "value": 2,
+                },
+              ]
+            }
+            value={1}
+          />
+        </div>
+      </td>
+      <td>
+        <button
+          className="btn btn-danger btn-small"
+          onClick={[Function]}
+        >
+          <i
+            className="fa fa-remove"
+          />
+        </button>
+      </td>
+    </tr>
+  </tbody>
+</table>
+`;

+ 7 - 4
public/app/types/datasources.ts

@@ -4,14 +4,17 @@ import { Plugin } from './plugins';
 export interface DataSourcePermission {
   id: number;
   datasourceId: number;
-  userId: number;
-  userLogin: string;
-  userEmail: string;
-  userAvatarUrl: string;
   permission: number;
   permissionName: string;
   created: string;
   updated: string;
+  userId?: number;
+  userLogin?: string;
+  userEmail?: string;
+  userAvatarUrl?: string;
+  teamId?: number;
+  teamAvatarUrl?: string;
+  team?: string;
 }
 
 export interface DataSourcePermissionDTO {