mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Typescript no-implicit any fixes progress (#17018)
* Chore: Typescript no-implicit any fixes progress * Fixed tests * Updated snapshot
This commit is contained in:
parent
813e3ffc15
commit
f12d47ef52
@ -55,11 +55,11 @@ export interface CommonProps<T> {
|
|||||||
onCloseMenu?: () => void;
|
onCloseMenu?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectProps<T> {
|
export interface SelectProps<T> extends CommonProps<T> {
|
||||||
options: Array<SelectOptionItem<T>>;
|
options: Array<SelectOptionItem<T>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AsyncProps<T> {
|
interface AsyncProps<T> extends CommonProps<T> {
|
||||||
defaultOptions: boolean;
|
defaultOptions: boolean;
|
||||||
loadOptions: (query: string) => Promise<Array<SelectOptionItem<T>>>;
|
loadOptions: (query: string) => Promise<Array<SelectOptionItem<T>>>;
|
||||||
loadingMessage?: () => string;
|
loadingMessage?: () => string;
|
||||||
@ -95,9 +95,8 @@ export const MenuList = (props: any) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Select<T> extends PureComponent<CommonProps<T> & SelectProps<T>> {
|
export class Select<T> extends PureComponent<SelectProps<T>> {
|
||||||
static defaultProps = {
|
static defaultProps: Partial<SelectProps<any>> = {
|
||||||
width: null,
|
|
||||||
className: '',
|
className: '',
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isSearchable: true,
|
isSearchable: true,
|
||||||
@ -108,7 +107,7 @@ export class Select<T> extends PureComponent<CommonProps<T> & SelectProps<T>> {
|
|||||||
isLoading: false,
|
isLoading: false,
|
||||||
backspaceRemovesValue: true,
|
backspaceRemovesValue: true,
|
||||||
maxMenuHeight: 300,
|
maxMenuHeight: 300,
|
||||||
menuIsOpen: false,
|
isOpen: false,
|
||||||
components: {
|
components: {
|
||||||
Option: SelectOption,
|
Option: SelectOption,
|
||||||
SingleValue,
|
SingleValue,
|
||||||
@ -201,9 +200,8 @@ export class Select<T> extends PureComponent<CommonProps<T> & SelectProps<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AsyncSelect<T> extends PureComponent<CommonProps<T> & AsyncProps<T>> {
|
export class AsyncSelect<T> extends PureComponent<AsyncProps<T>> {
|
||||||
static defaultProps = {
|
static defaultProps: Partial<AsyncProps<any>> = {
|
||||||
width: null,
|
|
||||||
className: '',
|
className: '',
|
||||||
components: {},
|
components: {},
|
||||||
loadingMessage: () => 'Loading...',
|
loadingMessage: () => 'Loading...',
|
||||||
|
@ -7,11 +7,13 @@ export interface NavModelItem {
|
|||||||
id?: string;
|
id?: string;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
hideFromTabs?: boolean;
|
hideFromTabs?: boolean;
|
||||||
|
hideFromMenu?: boolean;
|
||||||
divider?: boolean;
|
divider?: boolean;
|
||||||
children?: NavModelItem[];
|
children?: NavModelItem[];
|
||||||
breadcrumbs?: NavModelBreadcrumb[];
|
breadcrumbs?: NavModelBreadcrumb[];
|
||||||
target?: string;
|
target?: string;
|
||||||
parentItem?: NavModelItem;
|
parentItem?: NavModelItem;
|
||||||
|
showOrgSwitcher?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NavModel {
|
export interface NavModel {
|
||||||
|
@ -4,7 +4,6 @@ import { AnnotationQueryEditor as StackdriverAnnotationQueryEditor } from 'app/p
|
|||||||
import { PasswordStrength } from './components/PasswordStrength';
|
import { PasswordStrength } from './components/PasswordStrength';
|
||||||
import PageHeader from './components/PageHeader/PageHeader';
|
import PageHeader from './components/PageHeader/PageHeader';
|
||||||
import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA';
|
import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA';
|
||||||
import { SearchResult } from './components/search/SearchResult';
|
|
||||||
import { TagFilter } from './components/TagFilter/TagFilter';
|
import { TagFilter } from './components/TagFilter/TagFilter';
|
||||||
import { SideMenu } from './components/sidemenu/SideMenu';
|
import { SideMenu } from './components/sidemenu/SideMenu';
|
||||||
import { MetricSelect } from './components/Select/MetricSelect';
|
import { MetricSelect } from './components/Select/MetricSelect';
|
||||||
@ -20,7 +19,6 @@ export function registerAngularDirectives() {
|
|||||||
react2AngularDirective('appNotificationsList', AppNotificationList, []);
|
react2AngularDirective('appNotificationsList', AppNotificationList, []);
|
||||||
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
|
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
|
||||||
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
|
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
|
||||||
react2AngularDirective('searchResult', SearchResult, []);
|
|
||||||
react2AngularDirective('searchField', SearchField, [
|
react2AngularDirective('searchField', SearchField, [
|
||||||
'query',
|
'query',
|
||||||
'autoFocus',
|
'autoFocus',
|
||||||
|
@ -4,11 +4,11 @@ import { AlertBox } from '../AlertBox/AlertBox';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
appNotification: AppNotification;
|
appNotification: AppNotification;
|
||||||
onClearNotification: (id) => void;
|
onClearNotification: (id: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AppNotificationItem extends Component<Props> {
|
export default class AppNotificationItem extends Component<Props> {
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return this.props.appNotification.id !== nextProps.appNotification.id;
|
return this.props.appNotification.id !== nextProps.appNotification.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,12 +20,12 @@ export class AppNotificationList extends PureComponent<Props> {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { notifyApp } = this.props;
|
const { notifyApp } = this.props;
|
||||||
|
|
||||||
appEvents.on('alert-warning', options => notifyApp(createWarningNotification(options[0], options[1])));
|
appEvents.on('alert-warning', (options: string[]) => notifyApp(createWarningNotification(options[0], options[1])));
|
||||||
appEvents.on('alert-success', options => notifyApp(createSuccessNotification(options[0], options[1])));
|
appEvents.on('alert-success', (options: string[]) => notifyApp(createSuccessNotification(options[0], options[1])));
|
||||||
appEvents.on('alert-error', options => notifyApp(createErrorNotification(options[0], options[1])));
|
appEvents.on('alert-error', (options: string[]) => notifyApp(createErrorNotification(options[0], options[1])));
|
||||||
}
|
}
|
||||||
|
|
||||||
onClearAppNotification = id => {
|
onClearAppNotification = (id: number) => {
|
||||||
this.props.clearAppNotification(id);
|
this.props.clearAppNotification(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,10 +14,10 @@ export interface Props {
|
|||||||
export default class OrgActionBar extends PureComponent<Props> {
|
export default class OrgActionBar extends PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { searchQuery, layoutMode, onSetLayoutMode, linkButton, setSearchQuery, target } = this.props;
|
const { searchQuery, layoutMode, onSetLayoutMode, linkButton, setSearchQuery, target } = this.props;
|
||||||
const linkProps = { href: linkButton.href, target: undefined };
|
const linkProps = { href: linkButton.href };
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
linkProps.target = target;
|
(linkProps as any).target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PageHeader from './PageHeader';
|
import PageHeader from './PageHeader';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow, ShallowWrapper } from 'enzyme';
|
||||||
|
|
||||||
describe('PageHeader', () => {
|
describe('PageHeader', () => {
|
||||||
let wrapper;
|
let wrapper: ShallowWrapper<PageHeader>;
|
||||||
|
|
||||||
describe('when the nav tree has a node with a title', () => {
|
describe('when the nav tree has a node with a title', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
@ -22,7 +22,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
|
|||||||
showPermissionLevels: true,
|
showPermissionLevels: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = this.getCleanState();
|
this.state = this.getCleanState();
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onTypeChanged = evt => {
|
onTypeChanged = (evt: any) => {
|
||||||
const type = evt.target.value as AclTarget;
|
const type = evt.target.value as AclTarget;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -65,7 +65,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
|
|||||||
this.setState({ permission: permission.value });
|
this.setState({ permission: permission.value });
|
||||||
};
|
};
|
||||||
|
|
||||||
onSubmit = async evt => {
|
onSubmit = async (evt: React.SyntheticEvent) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
await this.props.onAddPermission(this.state);
|
await this.props.onAddPermission(this.state);
|
||||||
this.setState(this.getCleanState());
|
this.setState(this.getCleanState());
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { Select } from '@grafana/ui';
|
import { Select, SelectOptionItem } from '@grafana/ui';
|
||||||
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
|
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
|
||||||
import { FolderInfo } from 'app/types';
|
import { FolderInfo } from 'app/types';
|
||||||
|
|
||||||
const setClassNameHelper = inherited => {
|
const setClassNameHelper = (inherited: boolean) => {
|
||||||
return inherited ? 'gf-form-disabled' : '';
|
return inherited ? 'gf-form-disabled' : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
function ItemAvatar({ item }) {
|
function ItemAvatar({ item }: { item: DashboardAcl }) {
|
||||||
if (item.userAvatarUrl) {
|
if (item.userAvatarUrl) {
|
||||||
return <img className="filter-table__avatar" src={item.userAvatarUrl} />;
|
return <img className="filter-table__avatar" src={item.userAvatarUrl} />;
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ function ItemAvatar({ item }) {
|
|||||||
return <i style={{ width: '25px', height: '25px' }} className="gicon gicon-viewer" />;
|
return <i style={{ width: '25px', height: '25px' }} className="gicon gicon-viewer" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemDescription({ item }) {
|
function ItemDescription({ item }: { item: DashboardAcl }) {
|
||||||
if (item.userId) {
|
if (item.userId) {
|
||||||
return <span className="filter-table__weak-italic">(User)</span>;
|
return <span className="filter-table__weak-italic">(User)</span>;
|
||||||
}
|
}
|
||||||
@ -39,8 +39,8 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class PermissionsListItem extends PureComponent<Props> {
|
export default class PermissionsListItem extends PureComponent<Props> {
|
||||||
onPermissionChanged = option => {
|
onPermissionChanged = (option: SelectOptionItem<PermissionLevel>) => {
|
||||||
this.props.onPermissionChanged(this.props.item, option.value as PermissionLevel);
|
this.props.onPermissionChanged(this.props.item, option.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
onRemoveItem = () => {
|
onRemoveItem = () => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
// @ts-ignore
|
||||||
import Remarkable from 'remarkable';
|
import Remarkable from 'remarkable';
|
||||||
import { getBackendSrv } from '../../services/backend_srv';
|
import { getBackendSrv } from '../../services/backend_srv';
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ export class PluginHelp extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
getBackendSrv()
|
getBackendSrv()
|
||||||
.get(`/api/plugins/${plugin.id}/markdown/${type}`)
|
.get(`/api/plugins/${plugin.id}/markdown/${type}`)
|
||||||
.then(response => {
|
.then((response: string) => {
|
||||||
const markdown = new Remarkable();
|
const markdown = new Remarkable();
|
||||||
const helpHtml = markdown.render(response);
|
const helpHtml = markdown.render(response);
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ interface State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MetricSelect extends React.Component<Props, State> {
|
export class MetricSelect extends React.Component<Props, State> {
|
||||||
static defaultProps = {
|
static defaultProps: Partial<Props> = {
|
||||||
variables: [],
|
variables: [],
|
||||||
options: [],
|
options: [],
|
||||||
isSearchable: true,
|
isSearchable: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { options: [] };
|
this.state = { options: [] };
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ export class MetricSelect extends React.Component<Props, State> {
|
|||||||
return nextProps.value !== this.props.value || !_.isEqual(nextOptions, this.state.options);
|
return nextProps.value !== this.props.value || !_.isEqual(nextOptions, this.state.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildOptions({ variables = [], options }) {
|
buildOptions({ variables = [], options }: Props) {
|
||||||
return variables.length > 0 ? [this.getVariablesGroup(), ...options] : options;
|
return variables.length > 0 ? [this.getVariablesGroup(), ...options] : options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
// @ts-ignore
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import { TeamPicker } from './TeamPicker';
|
import { TeamPicker } from './TeamPicker';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ export interface State {
|
|||||||
export class TeamPicker extends Component<Props, State> {
|
export class TeamPicker extends Component<Props, State> {
|
||||||
debouncedSearch: any;
|
debouncedSearch: any;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { isLoading: false };
|
this.state = { isLoading: false };
|
||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
@ -42,8 +42,8 @@ export class TeamPicker extends Component<Props, State> {
|
|||||||
query = '';
|
query = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return backendSrv.get(`/api/teams/search?perpage=10&page=1&query=${query}`).then(result => {
|
return backendSrv.get(`/api/teams/search?perpage=10&page=1&query=${query}`).then((result: any) => {
|
||||||
const teams = result.teams.map(team => {
|
const teams = result.teams.map((team: any) => {
|
||||||
return {
|
return {
|
||||||
id: team.id,
|
id: team.id,
|
||||||
value: team.id,
|
value: team.id,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
// @ts-ignore
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import { UserPicker } from './UserPicker';
|
import { UserPicker } from './UserPicker';
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ export interface State {
|
|||||||
export class UserPicker extends Component<Props, State> {
|
export class UserPicker extends Component<Props, State> {
|
||||||
debouncedSearch: any;
|
debouncedSearch: any;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { isLoading: false };
|
this.state = { isLoading: false };
|
||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
@ -45,8 +45,8 @@ export class UserPicker extends Component<Props, State> {
|
|||||||
|
|
||||||
return backendSrv
|
return backendSrv
|
||||||
.get(`/api/org/users?query=${query}&limit=10`)
|
.get(`/api/org/users?query=${query}&limit=10`)
|
||||||
.then(result => {
|
.then((result: any) => {
|
||||||
return result.map(user => ({
|
return result.map((user: any) => ({
|
||||||
id: user.userId,
|
id: user.userId,
|
||||||
value: user.userId,
|
value: user.userId,
|
||||||
label: user.login === user.email ? user.login : `${user.login} - ${user.email}`,
|
label: user.login === user.email ? user.login : `${user.login} - ${user.email}`,
|
||||||
|
@ -27,7 +27,7 @@ const timezones = [
|
|||||||
export class SharedPreferences extends PureComponent<Props, State> {
|
export class SharedPreferences extends PureComponent<Props, State> {
|
||||||
backendSrv: BackendSrv = getBackendSrv();
|
backendSrv: BackendSrv = getBackendSrv();
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -72,7 +72,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmitForm = async event => {
|
onSubmitForm = async (event: React.SyntheticEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const { homeDashboardId, theme, timezone } = this.state;
|
const { homeDashboardId, theme, timezone } = this.state;
|
||||||
|
@ -55,7 +55,7 @@ const DEFAULT_SNIPPETS = true;
|
|||||||
|
|
||||||
const editorTemplate = `<div></div>`;
|
const editorTemplate = `<div></div>`;
|
||||||
|
|
||||||
function link(scope, elem, attrs) {
|
function link(scope: any, elem: any, attrs: any) {
|
||||||
// Options
|
// Options
|
||||||
const langMode = attrs.mode || DEFAULT_MODE;
|
const langMode = attrs.mode || DEFAULT_MODE;
|
||||||
const maxLines = attrs.maxLines || DEFAULT_MAX_LINES;
|
const maxLines = attrs.maxLines || DEFAULT_MAX_LINES;
|
||||||
@ -116,7 +116,7 @@ function link(scope, elem, attrs) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Sync with outer scope - update editor content if model has been changed from outside of directive.
|
// Sync with outer scope - update editor content if model has been changed from outside of directive.
|
||||||
scope.$watch('content', (newValue, oldValue) => {
|
scope.$watch('content', (newValue: any, oldValue: any) => {
|
||||||
const editorValue = codeEditor.getValue();
|
const editorValue = codeEditor.getValue();
|
||||||
if (newValue !== editorValue && newValue !== oldValue) {
|
if (newValue !== editorValue && newValue !== oldValue) {
|
||||||
scope.$$postDigest(() => {
|
scope.$$postDigest(() => {
|
||||||
@ -142,7 +142,7 @@ function link(scope, elem, attrs) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function setLangMode(lang) {
|
function setLangMode(lang: string) {
|
||||||
ace.acequire('ace/ext/language_tools');
|
ace.acequire('ace/ext/language_tools');
|
||||||
codeEditor.setOptions({
|
codeEditor.setOptions({
|
||||||
enableBasicAutocompletion: true,
|
enableBasicAutocompletion: true,
|
||||||
@ -170,7 +170,7 @@ function link(scope, elem, attrs) {
|
|||||||
codeEditor.setTheme(theme);
|
codeEditor.setTheme(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setEditorContent(value) {
|
function setEditorContent(value: string) {
|
||||||
codeEditor.setValue(value);
|
codeEditor.setValue(value);
|
||||||
codeEditor.clearSelection();
|
codeEditor.clearSelection();
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@ export function spectrumPicker() {
|
|||||||
scope: true,
|
scope: true,
|
||||||
replace: true,
|
replace: true,
|
||||||
template: '<color-picker color="ngModel.$viewValue" onChange="onColorChange"></color-picker>',
|
template: '<color-picker color="ngModel.$viewValue" onChange="onColorChange"></color-picker>',
|
||||||
link: (scope, element, attrs, ngModel) => {
|
link: (scope: any, element: any, attrs: any, ngModel: any) => {
|
||||||
scope.ngModel = ngModel;
|
scope.ngModel = ngModel;
|
||||||
scope.onColorChange = color => {
|
scope.onColorChange = (color: string) => {
|
||||||
ngModel.$setViewValue(color);
|
ngModel.$setViewValue(color);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<div class="page-nav">
|
|
||||||
<div class="page-breadcrumbs">
|
|
||||||
<a class="breadcrumb-item active" href="/">
|
|
||||||
<i class="fa fa-home"></i>
|
|
||||||
</a>
|
|
||||||
<a class="breadcrumb-item" ng-href="{{::item.url}}" ng-repeat="item in ctrl.model.breadcrumbs">
|
|
||||||
{{::item.text}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<dashboard-search></dashboard-search>
|
|
@ -1,54 +0,0 @@
|
|||||||
import coreModule from '../../core_module';
|
|
||||||
import appEvents from 'app/core/app_events';
|
|
||||||
import { NavModel } from '@grafana/ui';
|
|
||||||
|
|
||||||
export class NavbarCtrl {
|
|
||||||
model: NavModel;
|
|
||||||
|
|
||||||
/** @ngInject */
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
showSearch() {
|
|
||||||
appEvents.emit('show-dash-search');
|
|
||||||
}
|
|
||||||
|
|
||||||
navItemClicked(navItem, evt) {
|
|
||||||
if (navItem.clickHandler) {
|
|
||||||
navItem.clickHandler();
|
|
||||||
evt.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function navbarDirective() {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
templateUrl: 'public/app/core/components/navbar/navbar.html',
|
|
||||||
controller: NavbarCtrl,
|
|
||||||
bindToController: true,
|
|
||||||
controllerAs: 'ctrl',
|
|
||||||
scope: {
|
|
||||||
model: '=',
|
|
||||||
},
|
|
||||||
link: (scope, elem) => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pageH1() {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
template: `
|
|
||||||
<h1 class="page-header__title">
|
|
||||||
<i class="page-header__icon {{::model.header.icon}}" ng-if="::model.header.icon"></i>
|
|
||||||
<img class="page-header__img" ng-src="{{::model.header.img}}" ng-if="::model.header.img"></i>
|
|
||||||
{{model.header.text}}
|
|
||||||
</h1>
|
|
||||||
`,
|
|
||||||
scope: {
|
|
||||||
model: '=',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
coreModule.directive('pageH1', pageH1);
|
|
||||||
coreModule.directive('navbar', navbarDirective);
|
|
@ -40,7 +40,7 @@ export class QueryPart {
|
|||||||
return this.def.renderer(this, innerExpr);
|
return this.def.renderer(this, innerExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasMultipleParamsInString(strValue, index) {
|
hasMultipleParamsInString(strValue: string, index: number) {
|
||||||
if (strValue.indexOf(',') === -1) {
|
if (strValue.indexOf(',') === -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ export class QueryPart {
|
|||||||
return this.def.params[index + 1] && this.def.params[index + 1].optional;
|
return this.def.params[index + 1] && this.def.params[index + 1].optional;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateParam(strValue, index) {
|
updateParam(strValue: string, index: number) {
|
||||||
// handle optional parameters
|
// handle optional parameters
|
||||||
// if string contains ',' and next param is optional, split and update both
|
// if string contains ',' and next param is optional, split and update both
|
||||||
if (this.hasMultipleParamsInString(strValue, index)) {
|
if (this.hasMultipleParamsInString(strValue, index)) {
|
||||||
@ -81,7 +81,7 @@ export class QueryPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function functionRenderer(part, innerExpr) {
|
export function functionRenderer(part: any, innerExpr: string) {
|
||||||
const str = part.def.type + '(';
|
const str = part.def.type + '(';
|
||||||
const parameters = _.map(part.params, (value, index) => {
|
const parameters = _.map(part.params, (value, index) => {
|
||||||
const paramType = part.def.params[index];
|
const paramType = part.def.params[index];
|
||||||
@ -105,14 +105,14 @@ export function functionRenderer(part, innerExpr) {
|
|||||||
return str + parameters.join(', ') + ')';
|
return str + parameters.join(', ') + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function suffixRenderer(part, innerExpr) {
|
export function suffixRenderer(part: QueryPartDef, innerExpr: string) {
|
||||||
return innerExpr + ' ' + part.params[0];
|
return innerExpr + ' ' + part.params[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function identityRenderer(part, innerExpr) {
|
export function identityRenderer(part: QueryPartDef, innerExpr: string) {
|
||||||
return part.params[0];
|
return part.params[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function quotedIdentityRenderer(part, innerExpr) {
|
export function quotedIdentityRenderer(part: QueryPartDef, innerExpr: string) {
|
||||||
return '"' + part.params[0] + '"';
|
return '"' + part.params[0] + '"';
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ const template = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
export function queryPartEditorDirective($compile, templateSrv) {
|
export function queryPartEditorDirective(templateSrv: any) {
|
||||||
const paramTemplate = '<input type="text" class="hide input-mini tight-form-func-param"></input>';
|
const paramTemplate = '<input type="text" class="hide input-mini tight-form-func-param"></input>';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -25,7 +25,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
handleEvent: '&',
|
handleEvent: '&',
|
||||||
debounce: '@',
|
debounce: '@',
|
||||||
},
|
},
|
||||||
link: function postLink($scope, elem) {
|
link: function postLink($scope: any, elem: any) {
|
||||||
const part = $scope.part;
|
const part = $scope.part;
|
||||||
const partDef = part.def;
|
const partDef = part.def;
|
||||||
const $paramsContainer = elem.find('.query-part-parameters');
|
const $paramsContainer = elem.find('.query-part-parameters');
|
||||||
@ -33,7 +33,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
|
|
||||||
$scope.partActions = [];
|
$scope.partActions = [];
|
||||||
|
|
||||||
function clickFuncParam(this: any, paramIndex) {
|
function clickFuncParam(this: any, paramIndex: number) {
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
const $link = $(this);
|
const $link = $(this);
|
||||||
const $input = $link.next();
|
const $input = $link.next();
|
||||||
@ -53,7 +53,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputBlur(this: any, paramIndex) {
|
function inputBlur(this: any, paramIndex: number) {
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
const $input = $(this);
|
const $input = $(this);
|
||||||
const $link = $input.prev();
|
const $link = $input.prev();
|
||||||
@ -72,7 +72,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
$link.show();
|
$link.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputKeyPress(this: any, paramIndex, e) {
|
function inputKeyPress(this: any, paramIndex: number, e: any) {
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
if (e.which === 13) {
|
if (e.which === 13) {
|
||||||
inputBlur.call(this, paramIndex);
|
inputBlur.call(this, paramIndex);
|
||||||
@ -84,12 +84,12 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
this.style.width = (3 + this.value.length) * 8 + 'px';
|
this.style.width = (3 + this.value.length) * 8 + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTypeahead($input, param, paramIndex) {
|
function addTypeahead($input: JQuery, param: any, paramIndex: number) {
|
||||||
if (!param.options && !param.dynamicLookup) {
|
if (!param.options && !param.dynamicLookup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeaheadSource = (query, callback) => {
|
const typeaheadSource = (query: string, callback: any) => {
|
||||||
if (param.options) {
|
if (param.options) {
|
||||||
let options = param.options;
|
let options = param.options;
|
||||||
if (param.type === 'int') {
|
if (param.type === 'int') {
|
||||||
@ -101,7 +101,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$scope.$apply(() => {
|
$scope.$apply(() => {
|
||||||
$scope.handleEvent({ $event: { name: 'get-param-options' } }).then(result => {
|
$scope.handleEvent({ $event: { name: 'get-param-options' } }).then((result: any) => {
|
||||||
const dynamicOptions = _.map(result, op => {
|
const dynamicOptions = _.map(result, op => {
|
||||||
return _.escape(op.value);
|
return _.escape(op.value);
|
||||||
});
|
});
|
||||||
@ -116,7 +116,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
source: typeaheadSource,
|
source: typeaheadSource,
|
||||||
minLength: 0,
|
minLength: 0,
|
||||||
items: 1000,
|
items: 1000,
|
||||||
updater: value => {
|
updater: (value: string) => {
|
||||||
value = _.unescape(value);
|
value = _.unescape(value);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
inputBlur.call($input[0], paramIndex);
|
inputBlur.call($input[0], paramIndex);
|
||||||
@ -138,12 +138,12 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$scope.showActionsMenu = () => {
|
$scope.showActionsMenu = () => {
|
||||||
$scope.handleEvent({ $event: { name: 'get-part-actions' } }).then(res => {
|
$scope.handleEvent({ $event: { name: 'get-part-actions' } }).then((res: any) => {
|
||||||
$scope.partActions = res;
|
$scope.partActions = res;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.triggerPartAction = action => {
|
$scope.triggerPartAction = (action: string) => {
|
||||||
$scope.handleEvent({ $event: { name: 'action', action: action } });
|
$scope.handleEvent({ $event: { name: 'action', action: action } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
// @ts-ignore
|
||||||
import baron from 'baron';
|
import baron from 'baron';
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ const scrollerClass = 'baron__scroller';
|
|||||||
export function geminiScrollbar() {
|
export function geminiScrollbar() {
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
link: (scope, elem, attrs) => {
|
link: (scope: any, elem: any, attrs: any) => {
|
||||||
let scrollRoot = elem.parent();
|
let scrollRoot = elem.parent();
|
||||||
const scroller = elem;
|
const scroller = elem;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
// @ts-ignore
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { SearchQuery } from './search';
|
import { SearchQuery } from './search';
|
||||||
import { css, cx } from 'emotion';
|
import { css, cx } from 'emotion';
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
export class SearchResult extends React.Component<any, any> {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
search: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return this.state.search.sections.map(section => {
|
|
||||||
return <SearchResultSection section={section} key={section.id} />;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SectionProps {
|
|
||||||
section: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SearchResultSection extends React.Component<SectionProps, any> {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderItem(item) {
|
|
||||||
return (
|
|
||||||
<a className="search-item" href={item.url} key={item.id}>
|
|
||||||
<span className="search-item__icon">
|
|
||||||
<i className="fa fa-th-large" />
|
|
||||||
</span>
|
|
||||||
<span className="search-item__body">
|
|
||||||
<div className="search-item__body-title">{item.title}</div>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSection = () => {
|
|
||||||
this.props.section.toggle();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const collapseClassNames = classNames({
|
|
||||||
fa: true,
|
|
||||||
'fa-plus': !this.props.section.expanded,
|
|
||||||
'fa-minus': this.props.section.expanded,
|
|
||||||
'search-section__header__toggle': true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="search-section" key={this.props.section.id}>
|
|
||||||
<div className="search-section__header">
|
|
||||||
<i className={classNames('search-section__header__icon', this.props.section.icon)} />
|
|
||||||
<span className="search-section__header__text">{this.props.section.title}</span>
|
|
||||||
<i className={collapseClassNames} onClick={this.toggleSection} />
|
|
||||||
</div>
|
|
||||||
{this.props.section.expanded && (
|
|
||||||
<div className="search-section__items">{this.props.section.items.map(this.renderItem)}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import { contextSrv } from 'app/core/services/context_srv';
|
|||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
import { parse, SearchParserOptions, SearchParserResult } from 'search-query-parser';
|
import { parse, SearchParserOptions, SearchParserResult } from 'search-query-parser';
|
||||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
|
|
||||||
export interface SearchQuery {
|
export interface SearchQuery {
|
||||||
query: string;
|
query: string;
|
||||||
parsedQuery: SearchParserResult;
|
parsedQuery: SearchParserResult;
|
||||||
@ -32,6 +33,11 @@ class SearchQueryParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SelectedIndicies {
|
||||||
|
dashboardIndex?: number;
|
||||||
|
folderIndex?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class SearchCtrl {
|
export class SearchCtrl {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
query: SearchQuery;
|
query: SearchQuery;
|
||||||
@ -49,7 +55,7 @@ export class SearchCtrl {
|
|||||||
queryParser: SearchQueryParser;
|
queryParser: SearchQueryParser;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) {
|
constructor($scope: any, private $location: any, private $timeout: any, private searchSrv: SearchSrv) {
|
||||||
appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
|
appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
|
||||||
appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);
|
appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);
|
||||||
appEvents.on('search-query', debounce(this.search.bind(this), 500), $scope);
|
appEvents.on('search-query', debounce(this.search.bind(this), 500), $scope);
|
||||||
@ -88,7 +94,7 @@ export class SearchCtrl {
|
|||||||
appEvents.emit('search-query');
|
appEvents.emit('search-query');
|
||||||
}
|
}
|
||||||
|
|
||||||
openSearch(evt, payload) {
|
openSearch(evt: any, payload: any) {
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
this.closeSearch();
|
this.closeSearch();
|
||||||
return;
|
return;
|
||||||
@ -166,7 +172,7 @@ export class SearchCtrl {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveSelection(direction) {
|
moveSelection(direction: number) {
|
||||||
if (this.results.length === 0) {
|
if (this.results.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -252,14 +258,14 @@ export class SearchCtrl {
|
|||||||
return query.query === '' && query.starred === false && query.tags.length === 0;
|
return query.query === '' && query.starred === false && query.tags.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
filterByTag(tag) {
|
filterByTag(tag: string) {
|
||||||
if (_.indexOf(this.query.tags, tag) === -1) {
|
if (_.indexOf(this.query.tags, tag) === -1) {
|
||||||
this.query.tags.push(tag);
|
this.query.tags.push(tag);
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTag(tag, evt) {
|
removeTag(tag: string, evt: any) {
|
||||||
this.query.tags = _.without(this.query.tags, tag);
|
this.query.tags = _.without(this.query.tags, tag);
|
||||||
this.search();
|
this.search();
|
||||||
this.giveSearchFocus = true;
|
this.giveSearchFocus = true;
|
||||||
@ -298,14 +304,11 @@ export class SearchCtrl {
|
|||||||
this.moveSelection(0);
|
this.moveSelection(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFlattenedResultForNavigation(): Array<{
|
private getFlattenedResultForNavigation(): SelectedIndicies[] {
|
||||||
folderIndex: number;
|
|
||||||
dashboardIndex: number;
|
|
||||||
}> {
|
|
||||||
let folderIndex = 0;
|
let folderIndex = 0;
|
||||||
|
|
||||||
return _.flatMap(this.results, s => {
|
return _.flatMap(this.results, (s: any) => {
|
||||||
let result = [];
|
let result: SelectedIndicies[] = [];
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
folderIndex: folderIndex,
|
folderIndex: folderIndex,
|
||||||
|
@ -10,15 +10,15 @@ export class SearchResultsCtrl {
|
|||||||
editable: boolean;
|
editable: boolean;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $location) {}
|
constructor(private $location: any) {}
|
||||||
|
|
||||||
toggleFolderExpand(section) {
|
toggleFolderExpand(section: any) {
|
||||||
if (section.toggle) {
|
if (section.toggle) {
|
||||||
if (!section.expanded && this.onFolderExpanding) {
|
if (!section.expanded && this.onFolderExpanding) {
|
||||||
this.onFolderExpanding();
|
this.onFolderExpanding();
|
||||||
}
|
}
|
||||||
|
|
||||||
section.toggle(section).then(f => {
|
section.toggle(section).then((f: any) => {
|
||||||
if (this.editable && f.expanded) {
|
if (this.editable && f.expanded) {
|
||||||
if (f.items) {
|
if (f.items) {
|
||||||
_.each(f.items, i => {
|
_.each(f.items, i => {
|
||||||
@ -34,7 +34,7 @@ export class SearchResultsCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToFolder(section, evt) {
|
navigateToFolder(section: any, evt: any) {
|
||||||
this.$location.path(section.url);
|
this.$location.path(section.url);
|
||||||
|
|
||||||
if (evt) {
|
if (evt) {
|
||||||
@ -43,7 +43,7 @@ export class SearchResultsCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSelection(item, evt) {
|
toggleSelection(item: any, evt: any) {
|
||||||
item.checked = !item.checked;
|
item.checked = !item.checked;
|
||||||
|
|
||||||
if (item.items) {
|
if (item.items) {
|
||||||
@ -62,14 +62,14 @@ export class SearchResultsCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemClick(item) {
|
onItemClick(item: any) {
|
||||||
//Check if one string can be found in the other
|
//Check if one string can be found in the other
|
||||||
if (this.$location.path().indexOf(item.url) > -1 || item.url.indexOf(this.$location.path()) > -1) {
|
if (this.$location.path().indexOf(item.url) > -1 || item.url.indexOf(this.$location.path()) > -1) {
|
||||||
appEvents.emit('hide-dash-search');
|
appEvents.emit('hide-dash-search');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectTag(tag, evt) {
|
selectTag(tag: any, evt: any) {
|
||||||
if (this.onTagSelected) {
|
if (this.onTagSelected) {
|
||||||
this.onTagSelected({ $tag: tag });
|
this.onTagSelected({ $tag: tag });
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@ jest.mock('../../app_events', () => ({
|
|||||||
const setup = (propOverrides?: object) => {
|
const setup = (propOverrides?: object) => {
|
||||||
const props = Object.assign(
|
const props = Object.assign(
|
||||||
{
|
{
|
||||||
link: {},
|
link: {
|
||||||
|
text: 'Hello',
|
||||||
|
},
|
||||||
user: {
|
user: {
|
||||||
id: 1,
|
id: 1,
|
||||||
isGrafanaAdmin: false,
|
isGrafanaAdmin: false,
|
||||||
@ -87,9 +89,9 @@ describe('Functions', () => {
|
|||||||
const wrapper = setup();
|
const wrapper = setup();
|
||||||
const mockEvent = { preventDefault: jest.fn() };
|
const mockEvent = { preventDefault: jest.fn() };
|
||||||
it('should emit show modal event if url matches shortcut', () => {
|
it('should emit show modal event if url matches shortcut', () => {
|
||||||
const child = { url: '/shortcuts' };
|
const child = { url: '/shortcuts', text: 'hello' };
|
||||||
const instance = wrapper.instance() as BottomNavLinks;
|
const instance = wrapper.instance() as BottomNavLinks;
|
||||||
instance.itemClicked(mockEvent, child);
|
instance.itemClicked(mockEvent as any, child);
|
||||||
|
|
||||||
expect(appEvents.emit).toHaveBeenCalledWith('show-modal', { templateHtml: '<help-modal></help-modal>' });
|
expect(appEvents.emit).toHaveBeenCalledWith('show-modal', { templateHtml: '<help-modal></help-modal>' });
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import appEvents from '../../app_events';
|
import appEvents from '../../app_events';
|
||||||
import { User } from '../../services/context_srv';
|
import { User } from '../../services/context_srv';
|
||||||
|
import { NavModelItem } from '@grafana/ui';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
link: any;
|
link: NavModelItem;
|
||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BottomNavLinks extends PureComponent<Props> {
|
class BottomNavLinks extends PureComponent<Props> {
|
||||||
itemClicked = (event, child) => {
|
itemClicked = (event: React.SyntheticEvent, child: NavModelItem) => {
|
||||||
if (child.url === '/shortcuts') {
|
if (child.url === '/shortcuts') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
appEvents.emit('show-modal', {
|
appEvents.emit('show-modal', {
|
||||||
@ -57,7 +58,7 @@ class BottomNavLinks extends PureComponent<Props> {
|
|||||||
link.children.map((child, index) => {
|
link.children.map((child, index) => {
|
||||||
if (!child.hideFromMenu) {
|
if (!child.hideFromMenu) {
|
||||||
return (
|
return (
|
||||||
<li className={child.divider} key={`${child.text}-${index}`}>
|
<li key={`${child.text}-${index}`}>
|
||||||
<a href={child.url} target={child.target} onClick={event => this.itemClicked(event, child)}>
|
<a href={child.url} target={child.target} onClick={event => this.itemClicked(event, child)}>
|
||||||
{child.icon && <i className={child.icon} />}
|
{child.icon && <i className={child.icon} />}
|
||||||
{child.text}
|
{child.text}
|
||||||
|
@ -4,10 +4,11 @@ import SignIn from './SignIn';
|
|||||||
import BottomNavLinks from './BottomNavLinks';
|
import BottomNavLinks from './BottomNavLinks';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
import { NavModelItem } from '@grafana/ui';
|
||||||
|
|
||||||
export default function BottomSection() {
|
export default function BottomSection() {
|
||||||
const navTree: any = _.cloneDeep(config.bootData.navTree);
|
const navTree: NavModelItem[] = _.cloneDeep(config.bootData.navTree);
|
||||||
const bottomNav: any = _.filter(navTree, item => item.hideFromMenu);
|
const bottomNav: NavModelItem[] = _.filter(navTree, item => item.hideFromMenu);
|
||||||
const isSignedIn = contextSrv.isSignedIn;
|
const isSignedIn = contextSrv.isSignedIn;
|
||||||
const user = contextSrv.user;
|
const user = contextSrv.user;
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import DropDownChild from './DropDownChild';
|
import DropDownChild from './DropDownChild';
|
||||||
|
import { NavModelItem } from '@grafana/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
link: any;
|
link: NavModelItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SideMenuDropDown: FC<Props> = props => {
|
const SideMenuDropDown: FC<Props> = props => {
|
||||||
|
@ -67,7 +67,9 @@ exports[`Render should render component 1`] = `
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="sidemenu-item-text"
|
className="sidemenu-item-text"
|
||||||
/>
|
>
|
||||||
|
Hello
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +20,6 @@ import { colors } from '@grafana/ui/';
|
|||||||
|
|
||||||
import { searchDirective } from './components/search/search';
|
import { searchDirective } from './components/search/search';
|
||||||
import { infoPopover } from './components/info_popover';
|
import { infoPopover } from './components/info_popover';
|
||||||
import { navbarDirective } from './components/navbar/navbar';
|
|
||||||
import { arrayJoin } from './directives/array_join';
|
import { arrayJoin } from './directives/array_join';
|
||||||
import { liveSrv } from './live/live_srv';
|
import { liveSrv } from './live/live_srv';
|
||||||
import { Emitter } from './utils/emitter';
|
import { Emitter } from './utils/emitter';
|
||||||
@ -56,7 +55,6 @@ export {
|
|||||||
registerAngularDirectives,
|
registerAngularDirectives,
|
||||||
arrayJoin,
|
arrayJoin,
|
||||||
coreModule,
|
coreModule,
|
||||||
navbarDirective,
|
|
||||||
searchDirective,
|
searchDirective,
|
||||||
liveSrv,
|
liveSrv,
|
||||||
layoutSelector,
|
layoutSelector,
|
||||||
|
@ -97,9 +97,9 @@ exports[`Render when feature toggle editorsCanAdmin is turned off should not ren
|
|||||||
isDisabled={false}
|
isDisabled={false}
|
||||||
isLoading={false}
|
isLoading={false}
|
||||||
isMulti={false}
|
isMulti={false}
|
||||||
|
isOpen={false}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
maxMenuHeight={300}
|
maxMenuHeight={300}
|
||||||
menuIsOpen={false}
|
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
openMenuOnFocus={false}
|
openMenuOnFocus={false}
|
||||||
options={
|
options={
|
||||||
@ -123,7 +123,6 @@ exports[`Render when feature toggle editorsCanAdmin is turned off should not ren
|
|||||||
"value": 0,
|
"value": 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width={null}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -183,9 +182,9 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render p
|
|||||||
isDisabled={false}
|
isDisabled={false}
|
||||||
isLoading={false}
|
isLoading={false}
|
||||||
isMulti={false}
|
isMulti={false}
|
||||||
|
isOpen={false}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
maxMenuHeight={300}
|
maxMenuHeight={300}
|
||||||
menuIsOpen={false}
|
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
openMenuOnFocus={false}
|
openMenuOnFocus={false}
|
||||||
options={
|
options={
|
||||||
@ -209,7 +208,6 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render p
|
|||||||
"value": 0,
|
"value": 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width={null}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -39,6 +39,8 @@ export interface DashboardAcl {
|
|||||||
name?: string;
|
name?: string;
|
||||||
inherited?: boolean;
|
inherited?: boolean;
|
||||||
sortRank?: number;
|
sortRank?: number;
|
||||||
|
userAvatarUrl?: string;
|
||||||
|
teamAvatarUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardPermissionInfo {
|
export interface DashboardPermissionInfo {
|
||||||
|
Loading…
Reference in New Issue
Block a user