Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Merge Master into Edge Feature Branch (#1073)
Browse files Browse the repository at this point in the history
* Dev Walkthru: add a new Panel to the Dashboard (#1062)

* Dev Walkthru: add a new Panel to the Dashboard

* small tweaks, review feedback

* fix bad code end marker

* Diagnostics bugFix (#1065)

* flatMap

* Dummy comment to retrigger build

* Add Rule Diagnostics (#1064)

Add diagnostics logging for rule create/update events. Added the following metrics:
Rule_NewClick
Rule_EditClick
Rule_DeviceGroupClick
Rule_CalculationClick
Rule_FieldClick
Rule_OperatorClick
Rule_AddConditionClick
Rule_SeverityLevelClick
Rule_StatusToggle
Rule_ApplyClick
Rule_CancelClick
Rule_TopXCloseClick

Also includes new "sessionid" sections of diagnostics call, which logs the time in ms since Jan 1, 1970 when the page was loaded (amplitude expects session id in this format). This fields will be added by diagnostics to enable logging of session id to amplitude--until those changes go in it will be ignored by the backend.
  • Loading branch information
isaac-dasan authored Aug 23, 2018
1 parent 04b2450 commit 0addf66
Show file tree
Hide file tree
Showing 31 changed files with 386 additions and 96 deletions.
1 change: 1 addition & 0 deletions docs/walkthrough/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following walkthroughs are available to help customize this application.
1. [Adding a New Service](addNewService.md)
1. [Adding a New Grid](addNewGrid.md)
1. [Adding a New Flyout](addNewFlyout.md)
1. [Adding a New Panel to the Dashboard](addNewDashboardPanel.md)


### Show the walkthrough examples in the running application
Expand Down
75 changes: 75 additions & 0 deletions docs/walkthrough/addNewDashboardPanel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
Walkthrough: Adding a New Panel to the Dashboard
================================================

The following is for creating a new panel called "**examplePanel**."

1. Create a folder named `examplePanel` inside the `components/pages/dashboard/panels` folder.
1. Create 3 files in the new folder. See the individual example files for more details and comments inline.
- [examplePanel.js](/src/components/pages/dashboard/panels/_examplePanel/examplePanel.js) - main component for the panel
- [examplePanel.scss](/src/components/pages/dashboard/panels/_examplePanel/examplePanel.scss) - styles for the new panel
- [index.js](/src/components/pages/dashboard/panels/_examplePanel/index.js) - exports for the new panel
1. Add the new panel to the main panel export file: [dashboard/panels/index.js](/src/components/pages/dashboard/panels/index.js).
```js
export * from './examplePanel';
```
1. Add the panel header to the translations file, [translations.json](../../public/locales/en/translations.json). [i18next][i18next] is used for internationalization.
```json
"examplePanel": {
"header": "Example Panel",
},
```
1. In the [examplePanel.js](/src/components/pages/dashboard/panels/_examplePanel/examplePanel.js), import the `Panel` components.
```js
import {
Panel,
PanelHeader,
PanelHeaderLabel,
PanelContent,
} from 'components/pages/dashboard/panel';
```
1. In the render method, use the various `Panel` components to ensure consistency with others. Then, add whatever components are needed inside `PanelContent`.
```jsx
<Panel>
<PanelHeader>
<PanelHeaderLabel>{t('examples.panel.header')}</PanelHeaderLabel>
</PanelHeader>
<PanelContent className="example-panel-container">
{t('examples.panel.panelBody')}
</PanelContent>
</Panel>
```
1. Add your panel to the [dashboard.js](/src/components/pages/dashboard/dashboard.js) page. Size the `Cell` for the panel according to how much space it will need. See [grid.scss](/src/components/pages/dashboard/grid/grid.scss) for the available grid-cell styles.
```jsx
<Cell className="col-4">
<ExamplePanel t={t} />
</Cell>
```
1. **Congratulations!** Run the application and navigate to the Dashboard page. You should see your new panel in action.

1. Now, you can edit the panel to do what you want. Send props with any data you need. If mapping data and actions from a reducer, consider using the "container" approach described in the [Adding a New Grid](addNewGrid.md) walkthrough.

1. Optional customizations:
1. Add an `Indicator` to the header to show pending state.
```jsx
{ isPending && <Indicator size="small" /> }
```
1. Use a `PanelOverlay` to show pending state. This example uses an `Indicator`, but other components or messages could be placed here.
```jsx
{ isPending && <PanelOverlay><Indicator /></PanelOverlay> }
```
1. Use `PanelError` and `AjaxError` to show error state.
```jsx
{ error && <PanelError><AjaxError t={t} error={error} /></PanelError> }
```

### More Information

- Explore the other remote monitoring [walkthroughs](README.md).
- Technology reference:
- [react][react]
- [i18next][i18next]



[i18next]: https://www.i18next.com/
[react]: https://reactjs.org/
2 changes: 1 addition & 1 deletion docs/walkthrough/addNewGrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Grids in remote monitoring are based on [ag-grid][ag-grid], with our own customi
t: this.props.t
};
```
1. Add the your grid and `RefreshBar to the `PageContent` (or in another component such as a flyout).
1. Add your grid and `RefreshBar` to the `PageContent` (or in another component such as a flyout).
```jsx
<PageContent className="grid-example-container" key="page-content">
<RefreshBar refresh={fetchData} time={lastUpdated} isPending={isPending} t={t} />
Expand Down
2 changes: 1 addition & 1 deletion docs/walkthrough/addNewService.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Services in remote monitoring are called using [rxjs][rxjs] Observables.
];
const rootEpic = combineEpics(...epics);
```
```
#### Congratulations! Your service is ready to be hooked up to user interface components.
Expand Down
4 changes: 4 additions & 0 deletions public/locales/en/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,10 @@
"close": "Close"
}
}
},
"panel": {
"header": "Example Panel",
"panelBody": "This is a new panel."
}
}
}
23 changes: 20 additions & 3 deletions src/components/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ if (Config.showWalkthroughExamples) {
tabConfigs.push(gridExampleTab);
}

class WalkthroughExampleRoute extends Component {
render() {
const { component: Component, ...props } = this.props

return (
<Route
{...props}
render={props => (
Config.showWalkthroughExamples ?
<Component {...props} /> :
<Redirect to='/' />
)}
/>
)
}
}

/** The base component for the app */
class App extends Component {

Expand Down Expand Up @@ -79,10 +96,10 @@ class App extends Component {
<Route exact path={rulesTab.to} component={RulesPage} />
<Route path={maintenanceTab.to} component={MaintenancePage} />
<Route path={packagesTab.to} component={PackagesPage} />
<Route path={exampleTab.to} component={ExamplePage} />
<Route path={flyoutExampleTab.to} component={FlyoutExamplePage} />
<Route path={gridExampleTab.to} component={GridExamplePage} />
<Route component={PageNotFound} />
<WalkthroughExampleRoute path={exampleTab.to} component={ExamplePage} />
<WalkthroughExampleRoute path={flyoutExampleTab.to} component={FlyoutExamplePage} />
<WalkthroughExampleRoute path={gridExampleTab.to} component={GridExamplePage} />
</Switch>
{this.props.deviceGroupFlyoutIsOpen && <ManageDeviceGroupsContainer />}
{this.state.openFlyout === 'settings' && <SettingsContainer onClose={this.closeFlyout} />}
Expand Down
3 changes: 2 additions & 1 deletion src/components/pages/dashboard/dashboard.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ const mapStateToProps = state => ({
// Wrap the dispatch method
const mapDispatchToProps = dispatch => ({
fetchRules: () => dispatch(rulesEpics.actions.fetchRules()),
updateTimeInterval: timeInterval => dispatch(appRedux.actions.updateTimeInterval(timeInterval))
updateTimeInterval: timeInterval => dispatch(appRedux.actions.updateTimeInterval(timeInterval)),
updateCurrentWindow: (currentWindow) => dispatch(appRedux.actions.updateCurrentWindow(currentWindow))
});

export const DashboardContainer = translate()(connect(mapStateToProps, mapDispatchToProps)(Dashboard));
8 changes: 8 additions & 0 deletions src/components/pages/dashboard/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
TelemetryPanel,
AnalyticsPanel,
MapPanel,
ExamplePanel,
transformTelemetryResponse,
chartColorObjects
} from './panels';
Expand Down Expand Up @@ -65,6 +66,8 @@ export class Dashboard extends Component {
this.dashboardRefresh$ = new Subject(); // Restarts all streams
this.telemetryRefresh$ = new Subject();
this.panelsRefresh$ = new Subject();

this.props.updateCurrentWindow('Dashboard');
}

componentDidMount() {
Expand Down Expand Up @@ -407,6 +410,11 @@ export class Dashboard extends Component {
colors={chartColorObjects}
t={t} />
</Cell>
{ Config.showWalkthroughExamples &&
<Cell className="col-4">
<ExamplePanel t={t} />
</Cell>
}
</Grid>
</PageContent>
];
Expand Down
3 changes: 2 additions & 1 deletion src/components/pages/dashboard/dashboard.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe('Dashboard Component', () => {
rulesError: undefined,
rulesIsPending: false,
fetchRules: () => {},
t: () => {}
t: () => {},
updateCurrentWindow: () => {}
};

const wrapper = shallow(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.

import React, { Component } from 'react';

import {
Panel,
PanelHeader,
PanelHeaderLabel,
PanelContent,
} from 'components/pages/dashboard/panel';

import './examplePanel.css';

export class ExamplePanel extends Component {
constructor(props) {
super(props);

this.state = { isPending: true };
}

render() {
const { t } = this.props;

return (
<Panel>
<PanelHeader>
<PanelHeaderLabel>{t('examples.panel.header')}</PanelHeaderLabel>
</PanelHeader>
<PanelContent className="example-panel-container">
{t('examples.panel.panelBody')}
</PanelContent>
</Panel>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.

@import 'src/styles/mixins';
@import 'src/styles/themes';

.example-panel-container {
display: flex;
flex-flow: column nowrap;
padding: 0 !important;

@include themify($themes) {
color: themed('colorContentTextDim');
}
}
3 changes: 3 additions & 0 deletions src/components/pages/dashboard/panels/_examplePanel/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Copyright (c) Microsoft. All rights reserved.

export * from './examplePanel';
1 change: 1 addition & 0 deletions src/components/pages/dashboard/panels/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

export * from './_examplePanel';
export * from './alerts';
export * from './overview';
export * from './map';
Expand Down
9 changes: 7 additions & 2 deletions src/components/pages/devices/devices.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
getDevicesLastUpdated,
getDevicesPendingStatus
} from 'store/reducers/devicesReducer';
import { getDeviceGroups, getDeviceGroupError } from 'store/reducers/appReducer';
import {
redux as appRedux,
getDeviceGroups,
getDeviceGroupError
} from 'store/reducers/appReducer';

// Pass the devices status
const mapStateToProps = state => ({
Expand All @@ -24,7 +28,8 @@ const mapStateToProps = state => ({

// Wrap the dispatch method
const mapDispatchToProps = dispatch => ({
fetchDevices: () => dispatch(devicesEpics.actions.fetchDevices())
fetchDevices: () => dispatch(devicesEpics.actions.fetchDevices()),
updateCurrentWindow: (currentWindow) => dispatch(appRedux.actions.updateCurrentWindow(currentWindow))
});

export const DevicesContainer = translate()(connect(mapStateToProps, mapDispatchToProps)(Devices));
2 changes: 2 additions & 0 deletions src/components/pages/devices/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export class Devices extends Component {
...closedFlyoutState,
contextBtns: null
};

this.props.updateCurrentWindow('Devices');
}

componentWillReceiveProps(nextProps) {
Expand Down
1 change: 1 addition & 0 deletions src/components/pages/devices/devices.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe('Devices Component', () => {
fetchDevices: () => {},
changeDeviceGroup: (id) => {},
t: () => {},
updateCurrentWindow: () => {}
};

const wrapper = shallow(
Expand Down
5 changes: 4 additions & 1 deletion src/components/pages/maintenance/maintenance.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import { Maintenance } from './maintenance';
import {
epics as appEpics,
redux as appRedux,
getTheme,
getTimeInterval,
Expand Down Expand Up @@ -39,7 +40,9 @@ const mapStateToProps = state => ({
// Wrap the dispatch method
const mapDispatchToProps = dispatch => ({
fetchRules: () => dispatch(rulesEpics.actions.fetchRules()),
updateTimeInterval: timeInterval => dispatch(appRedux.actions.updateTimeInterval(timeInterval))
updateTimeInterval: timeInterval => dispatch(appRedux.actions.updateTimeInterval(timeInterval)),
updateCurrentWindow: (currentWindow) => dispatch(appRedux.actions.updateCurrentWindow(currentWindow)),
logEvent: diagnosticsModel => dispatch(appEpics.actions.logEvent(diagnosticsModel))
});

export const MaintenanceContainer = translate()(connect(mapStateToProps, mapDispatchToProps)(Maintenance));
4 changes: 3 additions & 1 deletion src/components/pages/maintenance/maintenance.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export class Maintenance extends Component {
this.props.fetchRules();
}

this.props.updateCurrentWindow('Maintenance');
this.subscriptions = [];
}

Expand Down Expand Up @@ -235,7 +236,8 @@ export class Maintenance extends Component {
refreshData: this.getData,
onTimeIntervalChange: this.onTimeIntervalChange,
timeInterval: this.props.timeInterval,
lastUpdated: this.state.lastUpdated
lastUpdated: this.state.lastUpdated,
logEvent: this.props.logEvent
};
const alertProps = {
isPending: rulesIsPending || alertsIsPending,
Expand Down
3 changes: 2 additions & 1 deletion src/components/pages/maintenance/maintenance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ describe('Dashboard Component', () => {
rulesLastUpdated: undefined,
deviceEntities: {},
fetchRules: () => {},
t: () => {}
t: () => {},
updateCurrentWindow: () => {}
};

const wrapper = shallow(
Expand Down
3 changes: 2 additions & 1 deletion src/components/pages/maintenance/ruleDetails/ruleDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,8 @@ export class RuleDetails extends Component {
onHardSelectChange={this.onHardSelectChange('rules')}
rowData={rule}
pagination={false}
refresh={this.props.fetchRules} />
refresh={this.props.fetchRules}
logEvent={this.props.logEvent} />

<h4 className="sub-heading">{ t('maintenance.alertOccurrences') }</h4>
<AlertOccurrencesGrid {...alertsGridProps} />
Expand Down
Loading

0 comments on commit 0addf66

Please sign in to comment.