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

Dev Walkthru: add a new Panel to the Dashboard #1062

Merged
merged 4 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not this change but addNewService.md has links at the bottom not in correct format.

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**."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it might be handy to explain what a panel is in the first place? Perhaps for someone looking to customize this might already be obvious though. What are your thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its a dashboard panel. I guess I could explicitly state that... but since the title says it and the code is all under the dashboard folder... it seemed redundant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that does. I think I was thinking more of what is a page, vs a panel vs a tab but that would probably be in the first readme not here so feel free to ignore.


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 @@ -566,6 +566,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 @@ -44,6 +44,23 @@ if (Config.showWalkthroughExamples) {
tabConfigs.push(gridExampleTab);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can things like this be moved below or to a separate file? Not a huge deal but I think example stuff shouldn't be the first things someone sees. In some instances like const flyoutExampleTab being near all the other tab configurations makes sense. But individual classes like this seems like they can be moved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The final location of the docs and sample code is still to be determined. For example, the doc folks want to put these with the rest of the docs (i.e. not in the code). Having working sample code is valuable though...and the docs folks can't do that. So the sample code might move to its own repo... or get removed altogether. For now, its not really worth moving to separate files or figuring out anything past what it there now... since it may ALL go away anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is fair enough

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 @@ -76,9 +93,9 @@ class App extends Component {
<Route exact path={devicesTab.to} component={DevicesPage} />
<Route exact path={rulesTab.to} component={RulesPage} />
<Route path={maintenanceTab.to} component={MaintenancePage} />
<Route path={exampleTab.to} component={ExamplePage} />
<Route path={flyoutExampleTab.to} component={FlyoutExamplePage} />
<Route path={gridExampleTab.to} component={GridExamplePage} />
<WalkthroughExampleRoute path={exampleTab.to} component={ExamplePage} />
<WalkthroughExampleRoute path={flyoutExampleTab.to} component={FlyoutExamplePage} />
<WalkthroughExampleRoute path={gridExampleTab.to} component={GridExamplePage} />
<Route component={PageNotFound} />
</Switch>
{ this.props.deviceGroupFlyoutIsOpen && <ManageDeviceGroupsContainer /> }
Expand Down
6 changes: 6 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 @@ -407,6 +408,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
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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The panel-container class already has these properties by default. Should we include both classes in the example panel so that the css isn't needed here? Or is the idea to have a guide on how to customize the display more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When they add real stuff to their panel, they'll need a place to put it. That's really why I created this file.

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