wip: progress

This commit is contained in:
Torkel Ödegaard
2019-02-03 14:53:42 +01:00
parent cba2ca5531
commit 2cb1733c59
6 changed files with 138 additions and 66 deletions

View File

@@ -16,6 +16,7 @@ export interface Props {
editview: string; editview: string;
isEditing: boolean; isEditing: boolean;
isFullscreen: boolean; isFullscreen: boolean;
$injector: any;
updateLocation: typeof updateLocation; updateLocation: typeof updateLocation;
} }
@@ -25,13 +26,29 @@ export class DashNav extends PureComponent<Props> {
}; };
onAddPanel = () => {}; onAddPanel = () => {};
onClose = () => {
this.props.updateLocation({
query: { editview: null, panelId: null, edit: null, fullscreen: null },
partial: true,
});
};
onOpenSettings = () => { onOpenSettings = () => {
this.props.updateLocation({ this.props.updateLocation({
query: { query: { editview: 'settings' },
editview: 'settings',
},
partial: true, partial: true,
}) });
};
onStarDashboard = () => {
const { $injector, dashboard } = this.props;
const dashboardSrv = $injector.get('dashboardSrv');
dashboardSrv.starDashboard(dashboard.id, dashboard.meta.isStarred).then(newState => {
dashboard.meta.isStarred = newState;
this.forceUpdate();
});
}; };
renderLoadingState() { renderLoadingState() {
@@ -48,15 +65,16 @@ export class DashNav extends PureComponent<Props> {
); );
} }
render() { render() {
let { dashboard } = this.props; const { dashboard, isFullscreen, editview } = this.props;
if (!dashboard) { if (!dashboard) {
return this.renderLoadingState(); return this.renderLoadingState();
} }
const haveFolder = dashboard.meta.folderId > 0; const haveFolder = dashboard.meta.folderId > 0;
const { canEdit, canSave, folderTitle, showSettings } = dashboard.meta; const { canEdit, canStar, canSave, folderTitle, showSettings, isStarred } = dashboard.meta;
return ( return (
<div className="navbar"> <div className="navbar">
@@ -95,53 +113,66 @@ export class DashNav extends PureComponent<Props> {
</button> </button>
)} )}
{canStar && (
<button
className="btn navbar-button navbar-button--star"
onClick={this.onStarDashboard}
title="Mark as favorite"
>
{isStarred && <i className="fa fa-star" />}
{!isStarred && <i className="fa fa-star-o" />}
</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"> // <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> // <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> // </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"> // <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> // <i class="fa fa-link"></i>
// </a> // </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"> // <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> // <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> // </button>
// </div> // </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>
//
} }
{(isFullscreen || editview) && (
<div className="navbar-buttons navbar-buttons--close">
<button
className="btn navbar-button navbar-button--primary"
onClick={this.onClose}
title="Back to dashboard"
>
<i className="fa fa-reply" />
</button>
</div>
)}
</div> </div>
</div> </div>
); );
} }
} }
const mapStateToProps = () => ({ const mapStateToProps = () => ({});
});
const mapDispatchToProps = { const mapDispatchToProps = {
updateLocation updateLocation,
}; };
export default connect(mapStateToProps, mapDispatchToProps)(DashNav); export default connect(mapStateToProps, mapDispatchToProps)(DashNav);

View File

@@ -60,8 +60,8 @@ export class DashboardPage extends PureComponent<Props, State> {
async componentDidMount() { async componentDidMount() {
this.props.initDashboard({ this.props.initDashboard({
injector: this.props.$injector, $injector: this.props.$injector,
scope: this.props.$scope, $scope: this.props.$scope,
urlSlug: this.props.urlSlug, urlSlug: this.props.urlSlug,
urlUid: this.props.urlUid, urlUid: this.props.urlUid,
urlType: this.props.urlType, urlType: this.props.urlType,
@@ -123,7 +123,7 @@ export class DashboardPage extends PureComponent<Props, State> {
fullscreen: null, fullscreen: null,
panelId: null, panelId: null,
}, },
partial: true partial: true,
}); });
} }
@@ -163,7 +163,7 @@ export class DashboardPage extends PureComponent<Props, State> {
} }
render() { render() {
const { dashboard, editview } = this.props; const { dashboard, editview, $injector } = this.props;
const { isSettingsOpening, isEditing, isFullscreen } = this.state; const { isSettingsOpening, isEditing, isFullscreen } = this.state;
const classes = classNames({ const classes = classNames({
@@ -173,7 +173,13 @@ export class DashboardPage extends PureComponent<Props, State> {
return ( return (
<div className={classes}> <div className={classes}>
<DashNav dashboard={dashboard} isEditing={isEditing} isFullscreen={isFullscreen} editview={editview} /> <DashNav
dashboard={dashboard}
isEditing={isEditing}
isFullscreen={isFullscreen}
editview={editview}
$injector={$injector}
/>
{!dashboard && this.renderLoadingState()} {!dashboard && this.renderLoadingState()}
{dashboard && this.renderDashboard()} {dashboard && this.renderDashboard()}
</div> </div>

View File

@@ -1,5 +1,4 @@
// Libaries // Libaries
import { StoreState } from 'app/types';
import { ThunkAction } from 'redux-thunk'; import { ThunkAction } from 'redux-thunk';
// Services & Utils // Services & Utils
@@ -13,6 +12,7 @@ import { loadPluginDashboards } from '../../plugins/state/actions';
import { notifyApp } from 'app/core/actions'; import { notifyApp } from 'app/core/actions';
// Types // Types
import { StoreState } from 'app/types';
import { import {
DashboardAcl, DashboardAcl,
DashboardAclDTO, DashboardAclDTO,
@@ -27,7 +27,6 @@ export const setDashboardLoadingState = actionCreatorFactory<DashboardLoadingSta
export const setDashboardModel = actionCreatorFactory<MutableDashboard>('SET_DASHBOARD_MODEL').create(); export const setDashboardModel = actionCreatorFactory<MutableDashboard>('SET_DASHBOARD_MODEL').create();
export type Action = ActionOf<DashboardAclDTO[]>; export type Action = ActionOf<DashboardAclDTO[]>;
export type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>; export type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
export function getDashboardPermissions(id: number): ThunkResult<void> { export function getDashboardPermissions(id: number): ThunkResult<void> {

View File

@@ -1,5 +1,6 @@
// Services & Utils // Services & Utils
import { createErrorNotification } from 'app/core/copy/appNotification'; import { createErrorNotification } from 'app/core/copy/appNotification';
import { getBackendSrv } from 'app/core/services/backend_srv';
// Actions // Actions
import { updateLocation } from 'app/core/actions'; import { updateLocation } from 'app/core/actions';
@@ -12,24 +13,53 @@ import { DashboardLoadingState } from 'app/types/dashboard';
import { DashboardModel } from './DashboardModel'; import { DashboardModel } from './DashboardModel';
export interface InitDashboardArgs { export interface InitDashboardArgs {
injector: any; $injector: any;
scope: any; $scope: any;
urlUid?: string; urlUid?: string;
urlSlug?: string; urlSlug?: string;
urlType?: string; urlType?: string;
} }
export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: InitDashboardArgs): ThunkResult<void> { async function redirectToNewUrl(slug: string, dispatch: any) {
return async dispatch => { const res = await getBackendSrv().getDashboardBySlug(slug);
const loaderSrv = injector.get('dashboardLoaderSrv');
dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching)); if (res) {
const url = locationUtil.stripBaseFromUrl(res.meta.url.replace('/d/', '/d-solo/'));
dispatch(updateLocation(url));
}
}
export function initDashboard({ $injector, $scope, urlUid, urlSlug, urlType }: InitDashboardArgs): ThunkResult<void> {
return async dispatch => {
// handle old urls with no uid
if (!urlUid && urlSlug) {
redirectToNewUrl(urlSlug, dispatch);
return;
}
let dashDTO = null; let dashDTO = null;
// set fetching state
dispatch(setDashboardLoadingState(DashboardLoadingState.Fetching));
try { try {
// fetch dashboard from api // if no uid or slug, load home dashboard
dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid); if (!urlUid && !urlSlug) {
dashDTO = await getBackendSrv().get('/api/dashboards/home');
if (dashDTO.redirectUri) {
const newUrl = locationUtil.stripBaseFromUrl(dashDTO.redirectUri);
dispatch(updateLocation({ path: newUrl }));
return;
} else {
dashDTO.meta.canSave = false;
dashDTO.meta.canShare = false;
dashDTO.meta.canStar = false;
}
} else {
const loaderSrv = $injector.get('dashboardLoaderSrv');
dashDTO = await loaderSrv.loadDashboard(urlType, urlSlug, urlUid);
}
} catch (err) { } catch (err) {
dispatch(setDashboardLoadingState(DashboardLoadingState.Error)); dispatch(setDashboardLoadingState(DashboardLoadingState.Error));
console.log(err); console.log(err);
@@ -50,13 +80,13 @@ export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: Ini
} }
// init services // init services
injector.get('timeSrv').init(dashboard); $injector.get('timeSrv').init(dashboard);
injector.get('annotationsSrv').init(dashboard); $injector.get('annotationsSrv').init(dashboard);
// template values service needs to initialize completely before // template values service needs to initialize completely before
// the rest of the dashboard can load // the rest of the dashboard can load
try { try {
await injector.get('variableSrv').init(dashboard); await $injector.get('variableSrv').init(dashboard);
} catch (err) { } catch (err) {
dispatch(notifyApp(createErrorNotification('Templating init failed', err.toString()))); dispatch(notifyApp(createErrorNotification('Templating init failed', err.toString())));
console.log(err); console.log(err);
@@ -68,11 +98,11 @@ export function initDashboard({ injector, scope, urlUid, urlSlug, urlType }: Ini
dashboard.autoFitPanels(window.innerHeight); dashboard.autoFitPanels(window.innerHeight);
// init unsaved changes tracking // init unsaved changes tracking
injector.get('unsavedChangesSrv').init(dashboard, scope); $injector.get('unsavedChangesSrv').init(dashboard, $scope);
scope.dashboard = dashboard; $scope.dashboard = dashboard;
injector.get('dashboardViewStateSrv').create(scope); $injector.get('dashboardViewStateSrv').create($scope);
injector.get('keybindingSrv').setupDashboardBindings(scope, dashboard); $injector.get('keybindingSrv').setupDashboardBindings($scope, dashboard);
} catch (err) { } catch (err) {
dispatch(notifyApp(createErrorNotification('Dashboard init failed', err.toString()))); dispatch(notifyApp(createErrorNotification('Dashboard init failed', err.toString())));
console.log(err); console.log(err);

View File

@@ -29,10 +29,12 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
$routeProvider $routeProvider
.when('/', { .when('/', {
templateUrl: 'public/app/partials/dashboard.html', template: '<react-container />',
controller: 'LoadDashboardCtrl',
reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
reloadOnSearch: false,
resolve: {
component: () => DashboardPage,
},
}) })
.when('/d/:uid/:slug', { .when('/d/:uid/:slug', {
template: '<react-container />', template: '<react-container />',
@@ -43,16 +45,20 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
}, },
}) })
.when('/d/:uid', { .when('/d/:uid', {
templateUrl: 'public/app/partials/dashboard.html', template: '<react-container />',
controller: 'LoadDashboardCtrl',
reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
reloadOnSearch: false,
resolve: {
component: () => DashboardPage,
},
}) })
.when('/dashboard/:type/:slug', { .when('/dashboard/:type/:slug', {
templateUrl: 'public/app/partials/dashboard.html', template: '<react-container />',
controller: 'LoadDashboardCtrl',
reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
reloadOnSearch: false,
resolve: {
component: () => DashboardPage,
},
}) })
.when('/d-solo/:uid/:slug', { .when('/d-solo/:uid/:slug', {
template: '<react-container />', template: '<react-container />',

View File

@@ -4,7 +4,7 @@ export interface MutableDashboard {
meta: { meta: {
fullscreen: boolean; fullscreen: boolean;
isEditing: boolean; isEditing: boolean;
} };
} }
export enum DashboardLoadingState { export enum DashboardLoadingState {