Skip to content
Snippets Groups Projects
Commit 95e3fd2a authored by Kyle Doherty's avatar Kyle Doherty
Browse files

Merge remote-tracking branch 'origin/release-0.16.0' into fix_fullscreen_text_fade

parents 0cfe4669 b3885800
No related branches found
No related tags found
No related merge requests found
Showing
with 131 additions and 62 deletions
......@@ -24,27 +24,55 @@ You can make as many dashboards as you want. Go nuts.
### How to Create a Dashboard
Once you have a question saved, you can create a dashboard. Click the **Dashboards** dropdown at the top of the screen, then **Create a new dashboard**. Give your new dashboard a name and a description, then click **Create**, and you’ll be taken to your shiny new dashboard. You can always get to your dashboards from the dropdown at the very top of the screen.
![Create Dashboard](images/dashboards/DashboardCreate.png)
### Adding saved questions to a dashboard
You can add a newly saved question to a dashboard directly from the window that pops up after you save the question, or by clicking the Add to Dashboard icon in the top-right of a question page. You can also go to one of your dashboards and click the plus icon in the top right to add any of your saved questions to the dashboard.
Once you add a question to your dashboard, it’ll look something like this:
![First Dashboard](images/FirstDashboard.png)
![First Dashboard](images/dashboards/FirstDashboard.png)
### Arranging cards
Each question on a dashboard is in its own card that you can move around or resize as you see fit; just click the edit icon that looks like a pencil in the top-right of the dashboard screen.
The lines around the card will change from solid to dotted, showing you that you’re in edit mode.
Once you're in edit mode you'll see a grid appear. You can move and resize the cards in the dashboard to your liking and they'll snap to the grid.
![Editing dashboard](images/dashboards/DashboardEdit.png)
![editmode](images/Editmode.png)
- To move cards just click and drag.
- To resize a card just click and drag the handle at the bottom right corner of the card.
- To remove a card, click the X icon in the top right corner.
Questions in your dashboard will automatically update their display based on the size you choose to make sure your data looks great at any size.
* To resize a card, hover your pointer over the lower right corner of it and click and drag.
* To reorder your cards, click on the card and drag it to where you want it to be. The other cards will rearrange themselves as you move the card around.
* To remove a card, click the trashcan icon on it.
## Deleting a dashboard
Deleting a dashboard does not delete the individual saved questions on it — it just deletes the dashboard. Remember — dashboards are shared by everyone on your team, so think twice before you delete something that someone else might be using!
To delete a dashboard, click the pencil-looking **Edit** icon in the top right of the dashboard, then click **Delete**.
## Fullscreen dashboards
After you've made your ideal dashboard you may want to put it on a TV or present it in some other visible space to help keep your team up-to-date throughout the day.
To enter fullscreen mode just click the fullscreen icon in the top right of the dashboard.
Once you've entered fullscreen mode you can also switch the dashboard into "Night mode" for higher contrast.
![Night mode](images/dashboards/DashboardNightMode.png)
## Auto refresh
If your data is more realtime in nature you can set your dashboard up to auto refresh.
![Autorefresh](images/dashboards/DashboardAutoRefresh.png)
You can set your dashboard to update in 1, 5, 10, 15, 30, and 60 minute intervals depending on how fresh you need the data to be.
Enabling auto refresh will re-run all the queries on the dashboard at the interval you choose, so keep the size of the dashboard and the complexity of the questions in mind when setting up auto refresh.
Combining fullscreen mode and auto refresh is a great way to keep your team in sync with your data throughout the day.
---
Next, we'll offer up some suggestions on how to create useful dashboards, in our [Tips on Dashboards](06-dashboard-tips.md).
# Getting answers in Slack with Metabot
You can already send data to Slack on a set schedule via [Pulses](http://www.metabase.com/docs/latest/users-guide/07-pulses) but what about when you need an answer right now? Say hello to Metabot.
Metabot helps add context to conversations you’re having in Slack by letting you insert results from Metabase.
## Connecting to Slack.
To use Metabot with Slack you’ll first need to connect Metabase to your Slack with an API token.
See [Setting up Slack](http://www.metabase.com/docs/v0.15.1/administration-guide/07-setting-up-slack) for more information.
## What can Metabot do?
Metabot can show individual questions and also lists of questions that have already been asked in Metabase.
If you ever need help remembering what Metabot can do, just type ```metabot help``` in Slack.
![Metabot help](images/metabot/MetabotHelp.png)
## Showing questions
To see a question from Metabase in Slack type
```metabot show "<question-name>"``` where question name is the title of one of saved questions. If you have several similarly named questions Metabot will ask you to differentiate between the two by typing the number next to the name.
![Metabot similar](images/metabot/MetabotSimilarItems.png)
That number is the ID number of the question in Metabase and if you find yourself using the same question over and over again you can save a bit of time by typing “metabot show 19.”
![Metabot show](images/metabot/MetabotShow.png)
## Listing questions
If you don’t have a sense of which questions you want to view in Slack, you can type ```metabot list``` to get a list of recent questions from your Metabase.
![Metabot show](images/metabot/MetabotList.png)
## To review
- [Connect to Slack](http://www.metabase.com/docs/latest/users-guide/07-pulses) to start using Metabot.
- Show data from Metabase in Slack using ```metabot show <question-id>```
- Search for questions by typing ```metabot show <search-term>```
- Get a list of questions by typing ```metabot list```
- ```metabot help``` lets you see everything Metabot can do if you forget or need more information
docs/users-guide/images/FirstDashboard.png

81.7 KiB

docs/users-guide/images/dashboards/DashboardAutorefresh.png

173 KiB

docs/users-guide/images/dashboards/DashboardCreate.png

46 KiB

docs/users-guide/images/dashboards/DashboardEdit.png

110 KiB

docs/users-guide/images/dashboards/DashboardNightMode.png

296 KiB

docs/users-guide/images/dashboards/FirstDashboard.png

244 KiB

docs/users-guide/images/metabot/MetabotHelp.png

60.9 KiB

docs/users-guide/images/metabot/MetabotList.png

256 KiB

docs/users-guide/images/metabot/MetabotShow.png

135 KiB

docs/users-guide/images/metabot/MetabotSimilarItems.png

111 KiB

......@@ -20,4 +20,6 @@
> [Visualizing multiple series](09-data-model-reference.md)
> [Get answers in Slack with Metabot](10-metabot.md)
Let's get started with an overview of [What Metabase does](01-what-is-metabase.md).
......@@ -99,6 +99,10 @@ export default class SettingsSlackForm extends Component {
this.setState({
formData: { ...this.state.formData, [element.key]: (MetabaseUtils.isEmpty(value)) ? null : value }
});
if (element.key === "metabot-enabled") {
MetabaseAnalytics.trackEvent("Slack Settings", "Toggle Metabot", value);
}
}
handleFormErrors(error) {
......
......@@ -290,6 +290,7 @@ CardControllers.controller('CardDetail', [
var dataReferenceModel = {
Metabase: Metabase,
closeFn: toggleDataReference,
setCardAndRun: (card) => setCard(card, {runQuery: true}),
runQueryFn: runQuery,
setQueryFn: onQueryChanged,
setDatabaseFn: setDatabase,
......
......@@ -4,6 +4,7 @@ import ReactDOM from "react-dom";
import DashboardHeader from "../components/DashboardHeader.jsx";
import DashboardGrid from "../components/DashboardGrid.jsx";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
import MetabaseAnalytics from "metabase/lib/analytics";
import screenfull from "screenfull";
......@@ -134,6 +135,7 @@ export default class Dashboard extends Component {
if (refreshPeriod != null) {
this._interval = setInterval(this.tickRefreshClock, TICK_PERIOD * 1000);
this.setState({ refreshPeriod, refreshElapsed: 0 });
MetabaseAnalytics.trackEvent("Dashboard", "Set Refresh", refreshPeriod);
} else {
this.setState({ refreshPeriod: null, refreshElapsed: null });
}
......
......@@ -134,7 +134,7 @@ export default class DashboardHeader extends Component {
ref="dashboardHistory"
triggerElement={
<Tooltip tooltip="Revision History">
<span>
<span data-metabase-event={"Dashboard;Revisions"}>
<Icon className="text-brand-hover" name="history" width="16px" height="16px" />
</span>
</Tooltip>
......@@ -190,14 +190,14 @@ export default class DashboardHeader extends Component {
if (!isEditing && !isEmpty) {
buttons.push(
<RefreshWidget className="text-brand-hover" key="refresh" period={this.props.refreshPeriod} elapsed={this.props.refreshElapsed} onChangePeriod={this.props.setRefreshPeriod} />
<RefreshWidget data-metabase-event="Dashboard;Refresh Menu Open" className="text-brand-hover" key="refresh" period={this.props.refreshPeriod} elapsed={this.props.refreshElapsed} onChangePeriod={this.props.setRefreshPeriod} />
);
}
if (!isEditing && isFullscreen) {
buttons.push(
<Tooltip tooltip={isNightMode ? "Daytime mode" : "Nighttime mode"}>
<span>
<span data-metabase-event={"Dashboard;Night Mode;"+!isNightMode}>
<NightModeIcon className="text-brand-hover cursor-pointer" key="night" isNightMode={isNightMode} onClick={() => this.props.onNightModeChange(!isNightMode) } />
</span>
</Tooltip>
......@@ -208,7 +208,7 @@ export default class DashboardHeader extends Component {
// option click to enter fullscreen without making the browser go fullscreen
buttons.push(
<Tooltip tooltip={isFullscreen ? "Exit fullscreen" : "Enter fullscreen"}>
<span>
<span data-metabase-event={"Dashboard;Fullscreen Mode;"+!isFullscreen}>
<FullscreenIcon className="text-brand-hover cursor-pointer" key="fullscreen" isFullscreen={isFullscreen} onClick={(e) => this.props.onFullscreenChange(!isFullscreen, !e.altKey)} />
</span>
</Tooltip>
......
......@@ -3,6 +3,8 @@ import React, { Component, PropTypes } from "react";
import DataReferenceQueryButton from './DataReferenceQueryButton.jsx';
import Icon from "metabase/components/Icon.jsx";
import Query from "metabase/lib/query";
import { createCard } from "metabase/lib/card";
import { createQuery } from "metabase/lib/query";
import { isDimension } from "metabase/lib/schema_metadata";
import inflection from 'inflection';
......@@ -28,9 +30,7 @@ export default class DataReferenceField extends Component {
loadTableFn: PropTypes.func.isRequired,
runQueryFn: PropTypes.func.isRequired,
setQueryFn: PropTypes.func.isRequired,
setDatabaseFn: PropTypes.func.isRequired,
setSourceTableFn: PropTypes.func.isRequired,
setDisplayFn: PropTypes.func.isRequired
setCardAndRun: PropTypes.func.isRequired
};
componentWillMount() {
......@@ -54,56 +54,45 @@ export default class DataReferenceField extends Component {
}
Query.addFilter(query.query);
Query.updateFilter(query.query, Query.getFilters(query.query).length - 1, [null, this.props.field.id, null]);
this.setQuery(query, false);
this.props.setQueryFn(query);
}
groupBy() {
var query = this.setDatabaseAndTable();
let query = this.props.query;
if (!Query.hasValidAggregation(query.query)) {
Query.updateAggregation(query.query, ["rows"]);
}
Query.addDimension(query.query);
Query.updateDimension(query.query, this.props.field.id, query.query.breakout.length - 1);
this.setQuery(query);
this.props.setQueryFn(query);
this.props.runQueryFn();
}
newCard() {
let card = createCard();
card.dataset_query = createQuery("query", this.state.table.db_id, this.state.table.id);
return card;
}
setQuerySum() {
var query = this.setDatabaseAndTable();
query.query.aggregation = ["sum", this.props.field.id];
query.query.breakout = [];
query.query.filter = [];
this.setQuery(query);
let card = this.newCard();
card.dataset_query.query.aggregation = ["sum", this.props.field.id];
this.props.setCardAndRun(card);
}
setQueryDistinct() {
var query = this.setDatabaseAndTable();
query.query.aggregation = ["rows"];
query.query.breakout = [this.props.field.id];
query.query.filter = [];
this.setQuery(query);
let card = this.newCard();
card.dataset_query.query.aggregation = ["rows"];
card.dataset_query.query.breakout = [this.props.field.id];
this.props.setCardAndRun(card);
}
setQueryCountGroupedBy(chartType) {
var query = this.setDatabaseAndTable();
query.query.aggregation = ["count"];
query.query.breakout = [this.props.field.id];
query.query.filter = [];
this.setQuery(query);
this.props.setDisplayFn(chartType);
}
setDatabaseAndTable() {
var query;
query = this.props.setDatabaseFn(this.state.table.db_id);
query = this.props.setSourceTableFn(this.state.table.id);
return query;
}
setQuery(query, run = true) {
this.props.setQueryFn(query);
if (run) {
this.props.runQueryFn();
}
let card = this.newCard();
card.dataset_query.query.aggregation = ["count"];
card.dataset_query.query.breakout = [this.props.field.id];
card.display = chartType;
this.props.setCardAndRun(card);
}
render() {
......@@ -125,20 +114,21 @@ export default class DataReferenceField extends Component {
// TODO: allow for filters/grouping via foreign keys
if (!query.query || query.query.source_table == undefined || query.query.source_table === field.table_id) {
useForCurrentQuestion.push(
<li key="filter-by" className="mt1">
<a className="Button Button--white text-default text-brand-hover border-brand-hover no-decoration" onClick={this.filterBy}>
<Icon className="mr1" name="add" width="12px" height="12px"/> Filter by {name}
</a>
</li>
);
// NOTE: disabled this for now because we need a way to capture the completed filter before adding it to the query, or to pop open the filter widget here?
// useForCurrentQuestion.push(
// <li key="filter-by" className="mt1">
// <a className="Button Button--white text-default text-brand-hover border-brand-hover no-decoration" onClick={this.filterBy}>
// <Icon className="mr1" name="add" width="12px" height="12px"/> Filter by {name}
// </a>
// </li>
// );
// current field must be a valid breakout option for this table AND cannot already be in the breakout clause of our query
if (validBreakout && (query.query.breakout && !_.contains(query.query.breakout, field.id))) {
if (validBreakout && this.state.table.id === this.props.query.query.source_table && (query.query.breakout && !_.contains(query.query.breakout, field.id))) {
useForCurrentQuestion.push(
<li key="group-by" className="mt1">
<a className="Button Button--white text-default text-brand-hover border-brand-hover no-decoration" onClick={this.groupBy}>
<Icon className="mr2" name="add" width="12px" height="12px" /> Group by {name}
<Icon className="mr1" name="add" width="12px" height="12px" /> Group by {name}
</a>
</li>
);
......
import React, { Component, PropTypes } from "react";
import DataReferenceQueryButton from './DataReferenceQueryButton.jsx';
import { createCard } from "metabase/lib/card";
import { createQuery } from "metabase/lib/query";
import { foreignKeyCountsByOriginTable } from 'metabase/lib/schema_metadata';
import inflection from 'inflection';
......@@ -23,10 +24,7 @@ export default class DataReferenceTable extends Component {
query: PropTypes.object.isRequired,
loadTableFn: PropTypes.func.isRequired,
closeFn: PropTypes.func.isRequired,
runQueryFn: PropTypes.func.isRequired,
setQueryFn: PropTypes.func.isRequired,
setDatabaseFn: PropTypes.func.isRequired,
setSourceTableFn: PropTypes.func.isRequired
setCardAndRun: PropTypes.func.isRequired
};
componentWillMount() {
......@@ -47,9 +45,9 @@ export default class DataReferenceTable extends Component {
}
setQueryAllRows() {
var query = createQuery("query", this.state.table.db_id, this.state.table.id);
this.props.setQueryFn(query);
this.props.runQueryFn();
let card = createCard();
card.dataset_query = createQuery("query", this.state.table.db_id, this.state.table.id);
this.props.setCardAndRun(card);
}
render() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment