Commit 8dec7468 by Torkel Ödegaard

Dashboard settings starting to work

parent 83937f59
import { Emitter } from './utils/emitter'; import { Emitter } from './utils/emitter';
const appEvents = new Emitter(); export const appEvents = new Emitter();
export default appEvents; export default appEvents;
// Libaries
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
// Utils & Services
import { appEvents } from 'app/core/app_events';
// State
import { updateLocation } from 'app/core/actions';
// Types
import { DashboardModel } from '../../state/DashboardModel';
export interface Props {
dashboard: DashboardModel | null;
updateLocation: typeof updateLocation;
}
export class DashNav extends PureComponent<Props> {
onOpenSearch = () => {
appEvents.emit('show-dash-search');
};
onAddPanel = () => {};
onOpenSettings = () => {
this.props.updateLocation({
query: {
editview: 'settings',
},
partial: true,
})
};
renderLoadingState() {
return (
<div className="navbar">
<div>
<a className="navbar-page-btn" onClick={this.onOpenSearch}>
<i className="gicon gicon-dashboard" />
Loading...
<i className="fa fa-caret-down" />
</a>
</div>
</div>
);
}
render() {
let { dashboard } = this.props;
if (!dashboard) {
return this.renderLoadingState();
}
const haveFolder = dashboard.meta.folderId > 0;
const { canEdit, canSave, folderTitle, showSettings } = dashboard.meta;
return (
<div className="navbar">
<div>
<a className="navbar-page-btn" onClick={this.onOpenSearch}>
<i className="gicon gicon-dashboard" />
{haveFolder && <span className="navbar-page-btn--folder">{folderTitle} / </span>}
{dashboard.title}
<i className="fa fa-caret-down" />
</a>
</div>
<div className="navbar__spacer" />
{/*
<div class="navbar-buttons navbar-buttons--playlist" ng-if="ctrl.playlistSrv.isPlaying">
<a class="navbar-button navbar-button--tight" ng-click="ctrl.playlistSrv.prev()"><i class="fa fa-step-backward"></i></a>
<a class="navbar-button navbar-button--tight" ng-click="ctrl.playlistSrv.stop()"><i class="fa fa-stop"></i></a>
<a class="navbar-button navbar-button--tight" ng-click="ctrl.playlistSrv.next()"><i class="fa fa-step-forward"></i></a>
</div>
*/}
<div className="navbar-buttons navbar-buttons--actions">
{canEdit && (
<button className="btn navbar-button navbar-button--add-panel" title="Add panel" onClick={this.onAddPanel}>
<i className="gicon gicon-add-panel" />
</button>
)}
{showSettings && (
<button
className="btn navbar-button navbar-button--settings"
onClick={this.onOpenSettings}
title="Dashboard Settings"
>
<i className="fa fa-cog" />
</button>
)}
{
// <button class="btn navbar-button navbar-button--star" ng-show="::ctrl.dashboard.meta.canStar" ng-click="ctrl.starDashboard()" bs-tooltip="'Mark as favorite'" data-placement="bottom">
// <i class="fa" ng-class="{'fa-star-o': !ctrl.dashboard.meta.isStarred, 'fa-star': ctrl.dashboard.meta.isStarred}"></i>
// </button>
//
// <button class="btn navbar-button navbar-button--share" ng-show="::ctrl.dashboard.meta.canShare" ng-click="ctrl.shareDashboard(0)" bs-tooltip="'Share dashboard'" data-placement="bottom">
// <i class="fa fa-share-square-o"></i></a>
// </button>
//
// <button class="btn navbar-button navbar-button--save" ng-show="ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
// <i class="fa fa-save"></i>
// </button>
//
// <a class="btn navbar-button navbar-button--snapshot-origin" ng-if="::ctrl.dashboard.snapshot.originalUrl" href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom">
// <i class="fa fa-link"></i>
// </a>
//
// <button class="btn navbar-button navbar-button--settings" ng-click="ctrl.toggleSettings()" bs-tooltip="'Dashboard Settings'" data-placement="bottom" ng-show="ctrl.dashboard.meta.showSettings">
// <i class="fa fa-cog"></i>
// </button>
// </div>
//
// <div class="navbar-buttons navbar-buttons--tv">
// <button class="btn navbar-button navbar-button--tv" ng-click="ctrl.toggleViewMode()" bs-tooltip="'Cycle view mode'" data-placement="bottom">
// <i class="fa fa-desktop"></i>
// </button>
// </div>
//
// <gf-time-picker class="gf-timepicker-nav" dashboard="ctrl.dashboard" ng-if="!ctrl.dashboard.timepicker.hidden"></gf-time-picker>
//
// <div class="navbar-buttons navbar-buttons--close">
// <button class="btn navbar-button navbar-button--primary" ng-click="ctrl.close()" bs-tooltip="'Back to dashboard'" data-placement="bottom">
// <i class="fa fa-reply"></i>
// </button>
// </div>
}
</div>
</div>
);
}
}
const mapStateToProps = () => ({
});
const mapDispatchToProps = {
updateLocation
};
export default connect(mapStateToProps, mapDispatchToProps)(DashNav);
export { DashNavCtrl } from './DashNavCtrl'; export { DashNavCtrl } from './DashNavCtrl';
import DashNav from './DashNav';
export { DashNav };
// Libaries
import React, { PureComponent } from 'react';
// Utils & Services
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
// Types
import { DashboardModel } from '../../state/DashboardModel';
export interface Props {
dashboard: DashboardModel | null;
}
export class DashboardSettings extends PureComponent<Props> {
element: HTMLElement;
angularCmp: AngularComponent;
componentDidMount() {
const loader = getAngularLoader();
const template = '<dashboard-settings dashboard="dashboard" class="dashboard-settings" />';
const scopeProps = { dashboard: this.props.dashboard };
this.angularCmp = loader.load(this.element, scopeProps, template);
}
componentWillUnmount() {
if (this.angularCmp) {
this.angularCmp.destroy();
}
}
render() {
return <div className="panel-height-helper" ref={element => this.element = element} />;
}
}
export { SettingsCtrl } from './SettingsCtrl'; export { SettingsCtrl } from './SettingsCtrl';
export { DashboardSettings } from './DashboardSettings';
// Libraries // Libraries
import React, { Component } from 'react'; import $ from 'jquery';
import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import classNames from 'classnames';
// Components // Components
import { LoadingPlaceholder } from '@grafana/ui'; import { LoadingPlaceholder } from '@grafana/ui';
import { DashboardGrid } from '../dashgrid/DashboardGrid'; import { DashboardGrid } from '../dashgrid/DashboardGrid';
import { DashNav } from '../components/DashNav';
import { DashboardSettings } from '../components/DashboardSettings';
// Redux // Redux
import { initDashboard } from '../state/initDashboard'; import { initDashboard } from '../state/initDashboard';
import { setDashboardModel } from '../state/actions';
// Types // Types
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
...@@ -20,22 +25,23 @@ interface Props { ...@@ -20,22 +25,23 @@ interface Props {
urlUid?: string; urlUid?: string;
urlSlug?: string; urlSlug?: string;
urlType?: string; urlType?: string;
editview: string;
$scope: any; $scope: any;
$injector: any; $injector: any;
initDashboard: typeof initDashboard; initDashboard: typeof initDashboard;
setDashboardModel: typeof setDashboardModel;
loadingState: DashboardLoadingState; loadingState: DashboardLoadingState;
dashboard: DashboardModel; dashboard: DashboardModel;
} }
interface State { interface State {
dashboard: DashboardModel | null; isSettingsOpening: boolean;
notFound: boolean;
} }
export class DashboardPage extends Component<Props, State> { export class DashboardPage extends PureComponent<Props, State> {
state: State = { state: State = {
dashboard: null, isSettingsOpening: false,
notFound: false, isSettingsOpen: false,
}; };
async componentDidMount() { async componentDidMount() {
...@@ -45,18 +51,82 @@ export class DashboardPage extends Component<Props, State> { ...@@ -45,18 +51,82 @@ export class DashboardPage extends Component<Props, State> {
urlSlug: this.props.urlSlug, urlSlug: this.props.urlSlug,
urlUid: this.props.urlUid, urlUid: this.props.urlUid,
urlType: this.props.urlType, urlType: this.props.urlType,
}) });
} }
render() { componentDidUpdate(prevProps: Props) {
const { loadingState, dashboard } = this.props; const { dashboard, editview } = this.props;
// when dashboard has loaded subscribe to somme events
if (prevProps.dashboard === null && dashboard) {
dashboard.events.on('view-mode-changed', this.onViewModeChanged);
// set initial fullscreen class state
this.setPanelFullscreenClass();
}
if (!prevProps.editview && editview) {
this.setState({ isSettingsOpening: true });
setTimeout(() => {
this.setState({ isSettingsOpening: false});
}, 10);
}
}
onViewModeChanged = () => {
this.setPanelFullscreenClass();
};
setPanelFullscreenClass() {
$('body').toggleClass('panel-in-fullscreen', this.props.dashboard.meta.fullscreen === true);
}
if (!dashboard) { componentWillUnmount() {
return <LoadingPlaceholder text={loadingState.toString()} />; if (this.props.dashboard) {
this.props.dashboard.destroy();
this.props.setDashboardModel(null);
} }
}
renderLoadingState() {
return <LoadingPlaceholder text="Loading" />;
}
renderDashboard() {
const { dashboard, editview } = this.props;
const classes = classNames({
'dashboard-container': true,
'dashboard-container--has-submenu': dashboard.meta.submenuEnabled
});
return (
<div className="scroll-canvas scroll-canvas--dashboard">
{dashboard && editview && <DashboardSettings dashboard={dashboard} />}
<div className={classes}>
<DashboardGrid dashboard={dashboard} />
</div>
</div>
);
}
render() {
const { dashboard, editview } = this.props;
const { isSettingsOpening } = this.state;
const classes = classNames({
'dashboard-page--settings-opening': isSettingsOpening,
'dashboard-page--settings-open': !isSettingsOpening && editview,
});
console.log(dashboard); return (
return <DashboardGrid dashboard={dashboard} /> <div className={classes}>
<DashNav dashboard={dashboard} />
{!dashboard && this.renderLoadingState()}
{dashboard && this.renderDashboard()}
</div>
);
} }
} }
...@@ -65,12 +135,14 @@ const mapStateToProps = (state: StoreState) => ({ ...@@ -65,12 +135,14 @@ const mapStateToProps = (state: StoreState) => ({
urlSlug: state.location.routeParams.slug, urlSlug: state.location.routeParams.slug,
urlType: state.location.routeParams.type, urlType: state.location.routeParams.type,
panelId: state.location.query.panelId, panelId: state.location.query.panelId,
editview: state.location.query.editview,
loadingState: state.dashboard.loadingState, loadingState: state.dashboard.loadingState,
dashboard: state.dashboard.model as DashboardModel, dashboard: state.dashboard.model as DashboardModel,
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
initDashboard initDashboard,
setDashboardModel
}; };
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DashboardPage)); export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DashboardPage));
...@@ -67,6 +67,7 @@ export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: Ini ...@@ -67,6 +67,7 @@ export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: Ini
dashboard.updateSubmenuVisibility(); dashboard.updateSubmenuVisibility();
dashboard.autoFitPanels(window.innerHeight); dashboard.autoFitPanels(window.innerHeight);
// init unsaved changes tracking
injector.get('unsavedChangesSrv').init(dashboard, scope); injector.get('unsavedChangesSrv').init(dashboard, scope);
scope.dashboard = dashboard; scope.dashboard = dashboard;
......
...@@ -31,7 +31,7 @@ export const dashboardReducer = reducerFactory(initialState) ...@@ -31,7 +31,7 @@ export const dashboardReducer = reducerFactory(initialState)
model: action.payload model: action.payload
}), }),
}) })
.create() .create();
export default { export default {
dashboard: dashboardReducer, dashboard: dashboardReducer,
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
opacity: 1; opacity: 1;
transition: opacity 300ms ease-in-out; transition: opacity 300ms ease-in-out;
} }
.dashboard-container {
display: none;
}
} }
.dashboard-settings__content { .dashboard-settings__content {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment