Skip to content
Snippets Groups Projects
Commit 47838385 authored by Tom Robinson's avatar Tom Robinson
Browse files

Merge tag 'v0.32.2' of github.com:metabase/metabase into fix-copy-dashboard

v0.32.2
parents 167e73dc 4480b24b
No related branches found
No related tags found
No related merge requests found
Showing
with 368 additions and 69 deletions
......@@ -41,7 +41,8 @@ jobs:
command: >
for file in `find ./src -type f -name '*.clj' | sort`;
do echo `md5sum $file` >> backend-checksums.txt;
done
done;
echo `md5sum $project.clj` >> backend-checksums.txt
- persist_to_workspace:
root: /home/circleci/
paths:
......
......@@ -2,7 +2,9 @@
;; Specify which arg is the docstring for certain macros
;; (Add more as needed)
(put 'defendpoint 'clojure-doc-string-elt 3)
(put 'defendpoint-async 'clojure-doc-string-elt 3)
(put 'api/defendpoint 'clojure-doc-string-elt 3)
(put 'api/defendpoint-async 'clojure-doc-string-elt 3)
(put 'defsetting 'clojure-doc-string-elt 2)
(put 'setting/defsetting 'clojure-doc-string-elt 2)
(put 's/defn 'clojure-doc-string-elt 2)
......@@ -13,7 +15,6 @@
(assert 1)
(assoc 1)
(ex-info 1)
(execute-sql! 2)
(expect 0)
(match 1)
(merge-with 1)
......
......@@ -59,3 +59,4 @@ bin/node_modules/
/backend-checksums.txt
.vscode
target/checksum.txt
/resources/frontend_client/app/locales
......@@ -9,14 +9,14 @@ Metabase is the easy, open source way for everyone in your company to ask questi
[![Gitter chat](https://badges.gitter.im/metabase/metabase.png)](https://gitter.im/metabase/metabase)
# Features
- 5 minute [setup](http://metabase.com/docs/latest/setting-up-metabase.html) (We're not kidding)
- Let anyone on your team [ask questions](http://metabase.com/docs/latest/users-guide/04-asking-questions.html) without knowing SQL
- Rich beautiful [dashboards](http://metabase.com/docs/latest/users-guide/06-sharing-answers.html) with auto refresh and fullscreen
- 5 minute [setup](https://metabase.com/docs/latest/setting-up-metabase.html) (We're not kidding)
- Let anyone on your team [ask questions](https://metabase.com/docs/latest/users-guide/04-asking-questions.html) without knowing SQL
- Rich beautiful [dashboards](https://metabase.com/docs/latest/users-guide/06-sharing-answers.html) with auto refresh and fullscreen
- SQL Mode for analysts and data pros
- Create canonical [segments and metrics](http://metabase.com/docs/latest/administration-guide/07-segments-and-metrics.html) for your team to use
- Send data to Slack or email on a schedule with [Pulses](http://metabase.com/docs/latest/users-guide/10-pulses.html)
- View data in Slack anytime with [MetaBot](http://metabase.com/docs/latest/users-guide/11-metabot.html)
- [Humanize data](http://metabase.com/docs/latest/administration-guide/03-metadata-editing.html) for your team by renaming, annotating and hiding fields
- Create canonical [segments and metrics](https://metabase.com/docs/latest/administration-guide/07-segments-and-metrics.html) for your team to use
- Send data to Slack or email on a schedule with [Pulses](https://metabase.com/docs/latest/users-guide/10-pulses.html)
- View data in Slack anytime with [MetaBot](https://metabase.com/docs/latest/users-guide/11-metabot.html)
- [Humanize data](https://metabase.com/docs/latest/administration-guide/03-metadata-editing.html) for your team by renaming, annotating and hiding fields
For more information check out [metabase.com](http://www.metabase.com)
......@@ -112,7 +112,7 @@ Metabase also allows you to hit our Query API directly from Javascript to integr
# Danger zone
The button below will deploy the branch where this README.md lives onto Heroku. Metabase developers use it to deploy branches of Metabase to test our PRs, etc. We DO NOT recommend you using this for production. Instead, please use a [stable build](http://metabase.com/start).
The button below will deploy the branch where this README.md lives onto Heroku. Metabase developers use it to deploy branches of Metabase to test our PRs, etc. We DO NOT recommend you using this for production. Instead, please use a [stable build](https://metabase.com/start).
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
......
......@@ -19,6 +19,20 @@ target_jar="$driver_project_dir/target/uberjar/$driver_jar"
parents=''
checksum_file="$driver_project_dir/target/checksum.txt"
################################ DELETING OLD INCORRECTLY BUILT DRIVERS ###############################
verify_existing_build() {
verification_failed=''
./bin/verify-driver "$driver" || verification_failed=true
if [ "$verification_failed" ]; then
echo 'No existing build, or existing build is invalid. (Re)building driver.'
# By removing the checksum it will force rebuilding the driver
rm -f "$checksum_file"
fi
}
######################################## CALCULATING CHECKSUMS ########################################
md5_command=''
......@@ -137,7 +151,7 @@ build_driver_uberjar() {
if [ ! -f "$target_jar" ]; then
echo "Error: could not find $target_jar. Build failed."
return -1
return -3
fi
}
......@@ -153,6 +167,26 @@ strip_and_compress() {
done
}
# copy finished JAR to the resources dir
copy_target_to_dest() {
echo "Copying $target_jar -> $dest_location"
cp "$target_jar" "$dest_location"
}
# check that JAR in resources dir looks correct
verify_build () {
verification_failed=''
./bin/verify-driver "$driver" || verification_failed=true
if [ "$verification_failed" ]; then
echo "./bin/build-driver.sh $driver FAILED."
rm -f "$checksum_file"
rm -f "$target_jar"
rm -f "$dest_location"
return -4
fi
}
# Save the checksum for the newly built JAR
save_checksum() {
echo "Saving checksum for source files to $checksum_file"
......@@ -160,22 +194,18 @@ save_checksum() {
echo "$checksum" > "$checksum_file"
}
copy_target_to_dest() {
# ok, finally, copy finished JAR to the resources dir
echo "Copying $target_jar -> $dest_location"
cp "$target_jar" "$dest_location"
}
# Runs all the steps needed to build the driver.
build_driver() {
delete_old_drivers &&
verify_existing_build &&
delete_old_drivers &&
install_metabase_core &&
build_metabase_uberjar &&
build_parents &&
build_driver_uberjar &&
strip_and_compress &&
save_checksum &&
copy_target_to_dest
copy_target_to_dest &&
verify_build &&
save_checksum
}
######################################## PUTTING IT ALL TOGETHER ########################################
......@@ -202,5 +232,5 @@ elif [ ! "$(checksum_is_same)" ]; then
build_driver || retry_clean_build
# Either way, always copy the target uberjar to the dest location
else
copy_target_to_dest
(copy_target_to_dest && verify_build) || retry_clean_build
fi
......@@ -19,12 +19,27 @@ if [ "$1" == clean ]; then
done
fi
for driver in `ls modules/drivers/ | sed 's|/$||'`; do # strip trailing slashes if `ls` is set to include them
# strip trailing slashes if `ls` is set to include them
drivers=`ls modules/drivers/ | sed 's|/$||'`
for driver in $drivers; do
echo "Build: $driver"
./bin/build-driver.sh "$driver"
if [ $? -ne 0 ]; then
build_failed=''
./bin/build-driver.sh "$driver" || build_failed=true
if [ "$build_failed" ]; then
echo "Failed to build driver $driver."
exit -1
fi
done
# Double-check that all drivers were built successfully
for driver in $drivers; do
verification_failed=''
./bin/verify-driver "$driver" || verification_failed=true
if [ "$verification_failed" ]; then
exit -2
fi
done
......@@ -43,7 +43,7 @@ if [ "$BUILD_TYPE" == "release" ]; then
echo "Building Docker image ${DOCKER_IMAGE} from official Metabase release ${MB_TAG}"
# download the official version of Metabase which matches our tag
curl -f -o ${BASEDIR}/metabase.jar http://downloads.metabase.com/${MB_TAG}/metabase.jar
curl -L -f -o ${BASEDIR}/metabase.jar http://downloads.metabase.com/${MB_TAG}/metabase.jar
if [[ $? -ne 0 ]]; then
echo "Download failed!"
......
#!/usr/bin/env bash
set -eu
POEDITOR_PROJECT_ID="200535"
echo "Uploading metabase.pot to POEditor..."
curl -X POST https://api.poeditor.com/v2/projects/upload \
-F api_token="${POEDITOR_API_TOKEN}" \
-F id="${POEDITOR_PROJECT_ID}" \
-F updating="terms" \
-F file=@"locales/metabase.pot"
#!/usr/bin/env node
// USAGE:
//
// POEDITOR_API_TOKEN=TOKEN ./bin/i18n/import-po-from-poeditor [LANG...]
//
// If no arguments are provided it updates existing locales in ./locales
const fs = require("fs");
const fsp = fs.promises;
const https = require("https");
const fetch = require("isomorphic-fetch");
const url = require("url");
const POEDITOR_API_TOKEN = process.env["POEDITOR_API_TOKEN"];
const POEDITOR_PROJECT_ID = "200535"; // Metabae POEditor project
// currently we don't support variants of language
const aliases = {
"pt-br": "pt",
"zh-CN": "zh",
};
async function main(args) {
const wanted = new Set(args.length > 0 ? args : await getExistingLanguages());
const other = [];
// list available languages
const { result: { languages } } = await poeditor("languages/list");
for (const language of languages) {
const code = aliases[language.code] || language.code;
if (wanted.has(code)) {
wanted.delete(code);
console.log(`Downloading: ${code} (${language.percentage}%)`);
// start an export
const { result: { url } } = await poeditor("projects/export", {
language: language.code,
type: "po",
});
// download the exported file
https.get(url, res =>
res.pipe(fs.createWriteStream(`./locales/${code}.po`)),
);
} else {
other.push(language);
}
}
// log others with large percentage complete
for (const language of other
.filter(l => l.percentage > 50)
.sort((a, b) => b.percentage - a.percentage)) {
console.log(`Other: ${language.code} (${language.percentage}%)`);
}
// log languages that are wanted but missing in POEditor
for (const code of wanted) {
console.log(`Missing: ${code}`);
}
if (wanted.size > 0) {
throw new Error("Some wanted language not found");
}
}
// simple API client for poeditor
function poeditor(command, params = {}) {
const uri = url.format({
protocol: "https",
hostname: "api.poeditor.com",
pathname: `/v2/${command}`,
});
const query = {
api_token: POEDITOR_API_TOKEN,
id: POEDITOR_PROJECT_ID,
...params,
};
return fetch(uri, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: url.format({ query }).replace(/^\?/, ""),
}).then(res => res.json());
}
async function getExistingLanguages() {
return (await fsp.readdir("./locales"))
.filter(f => /\.po$/.test(f))
.map(f => f.replace(/\.po$/, ""));
}
main(process.argv.slice(2)).then(null, console.warn);
#!/bin/sh
set -eu
# gettext installed via homebrew is "keg-only", add it to the PATH
if [ -d "/usr/local/opt/gettext/bin" ]; then
export PATH="/usr/local/opt/gettext/bin:$PATH"
fi
POT_NAME="locales/metabase.pot"
PO_NAME="locales/$1.po"
if [ $# -lt 1 ]; then
echo "USAGE: update-translation en_US"
exit 1
fi
if [ -f "$PO_NAME" ]; then
exec msgmerge -U "$PO_NAME" "$POT_NAME"
else
exec msginit -i "$POT_NAME" -o "$PO_NAME" -l "$1"
fi
#!/bin/sh
set -eu
./bin/i18n/update-translation-template
find locales -name "*.po" -exec sh -c './bin/i18n/update-translation $(basename {} .po)' \;
#! /usr/bin/env bash
set -euo pipefail
driver="$1"
if [ ! "$driver" ]; then
echo 'Usage: ./bin/verify-driver [driver]'
exit -1
fi
echo "Verifying $driver driver..."
driver_file="resources/modules/$driver.metabase-driver.jar"
echo "Checking whether $driver_file exists...."
if [ ! -f "$driver_file" ]; then
echo 'File does not exist. Driver verification failed.'
exit -2
fi
echo 'File exists.'
# This assumes that the driver's main namespace is {driver}.clj, which is not necessarily required. Namespace is
# determined by `load-namespace` in the plugin manifest
#
# TODO - this won't work for drivers that have slashes in the name, because of namespace munging
munged_driver=`echo "$driver" | sed 's/-/_/g'`
driver_main_class="metabase/driver/${munged_driver}__init.class"
echo "Checking whether driver contains main class file $driver_main_class..."
if [ `jar -tf "$driver_file" | grep "$driver_main_class"` ]; then
echo 'Main class file found.'
else
echo 'Main class file missing. Driver verification failed.'
exit -3
fi
echo "Checking whether driver contains plugin manifest..."
if [ `jar -tf "$driver_file" | grep 'metabase-plugin.yaml'` ]; then
echo 'Plugin manifest found.'
else
echo 'Plugin manifest missing. Driver verification failed.'
exit -4
fi
echo 'Driver verification successful.'
exit 0
#!/usr/bin/env bash
VERSION="v0.32.0-snapshot"
VERSION="v0.32.2"
# dynamically pull more interesting stuff from latest git commit
HASH=$(git show-ref --head --hash=7 head) # first 7 letters of hash should be enough; that's what GitHub uses
......
......@@ -26,5 +26,5 @@ These are additional settings you can fill in to pass user attributes to Metabas
---
## That's it!
Still need help? Feel free to reach out to us at the support email address you were provided.
## Next: Copying contents of one Metabase instance to another
Learn how to use [serialization](serialization.md) to create and load data dumps of the contents of a Metabase instance.
......@@ -15,8 +15,76 @@ Here's a breakdown of each of the settings:
**Identity Provider Certificate:** This is a an encoded certificate that we will use when connecting to the IDP provider URI. This will look like a big blob of text that you'll want to copy and paste carefully — the spacing is important!
#### Configuring your SAML identity provider
Metabase will automatically log in Users authenticated with your SAML
identity provider, but in order to do so the SAML assertion *must*
contain attributes for each User's first name, last name, and email. The assertion should look something like the following:
```
<saml2:Assertion
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id4170618837332381492734749" IssueInstant="2019-03-27T17:56:11.067Z" Version="2.0">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/Issuer</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">userName</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData NotOnOrAfter="2019-03-27T18:01:11.246Z" Recipient="https://metabase.mycompany.com/auth/sso"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2019-03-27T17:51:11.246Z" NotOnOrAfter="2019-03-27T18:01:11.246Z">
<saml2:AudienceRestriction>
<saml2:Audience>my-metabase-app</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2019-03-27T17:56:11.067Z">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
Cam
</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
Saul
</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
cam@metabse.com
</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
```
Most SAML identity providers we've used already include these
assertions by default, but some (such as Okta) must be configured to
include them. Here's an example of what your assertions configuration
should look like in Okta. (You can find this page by going to `Admin > Applications > Metabase > General > SAML Settings [Edit]`).
![Okta SAML Integration](images/saml-okta-setup.png)
You can use other attribute names for these attributes if so desired;
see the section below. The important thing is that first name (given
name), last name (surname), and email address are included as
attributes of the first assertion returned in the identity provider's
SAML response.
##### IMPORTANT NOTE!
The email address *attribute* is used to log in an end user into a
corresponding Metabase account (creating it if needed). Thus it is
extremely critical that this email address MUST NOT be editable by end
users themselves. Otherwise they could potentially access Metabase
accounts other than their own by changing their email address.
#### Settings for signing SSO requests (optional)
These are additional settings you can fill in to sign SSO requests to ensure they don’t get tampered with.
These are additional settings you can fill in to sign SSO requests to
ensure they don’t get tampered with.
**SAML keystore path:** the absolute path to the keystore file to use for signing SAML requests.
......
docs/enterprise-guide/images/saml-okta-setup.png

141 KiB

## Copying contents of one Metabase instance to another
Metabase's serialization feature allows you to create a snapshot, called a dump, of the contents of a Metabase instance that can then be loaded into another instance.
This lets you do things like create a set of dashboards in one Metabase instance and then easily copy those dashboards to a number of other Metabase instances that you've set up for your customers. You could also use this feature to enable a staging-to-production workflow for important dashboards or reports by dumping from a staging instance of Metabase and then loading that dump into your production instance(s). You can even put the dump files into version control and audit changes to them, as the YAML files contained within the dump are pretty readable.
### What gets dumped and loaded
**Currently, dumps consist of the following Metabase artifacts:**
* Collections
* Dashboards
* Saved questions
* Pulses
* Segments and Metrics defined in the Data Model
* Archived collections, dashboards, saved questions, or pulses
* Public sharing settings for questions and dashboards
**They also contain a number of system settings:**
* Admin Panel settings, except for permissions
* Database connection settings
* Data Model settings
**Dumps do _not_ contain:**
* Permission settings
* User accounts or settings
* Alerts on saved questions
* Personal Collections or their contents (except for the user specified with the `--user` flag; see below)
### Before creating or loading a dump
If your instance is currently running, you will need to stop it first before creating or loading a dump, unless your Metabase application database supports concurrent reads. The default application database type, H2, does not.
### Creating a data dump
To create a dump of a Metabase instance, use the following command in your terminal:
`java -jar metabase.jar dump [dump_name] --user [example@example.com]`
The optional `--user` flag is used to specify a default administrator account for cases when this dump is loaded into a blank Metabase instance. This user will also be marked as the creator of all artifacts that are copied over to the instance. This user's personal collection and its contents will also be included in the data dump. If this flag isn't specified, Metabase will assume that the instance into which you're loading already has an admin user (but the load will fail if there isn't an admin user).
### Loading a dump
Currently, you can only load dumps into a Metabase instance that were created from the same version of Metabase. To load a dump into a Metabase instance, use the following command, where `[my_dump]` is the path to the dump you want to load:
`java -jar metabase.jar load [my_dump] --mode [skip/update] --on-error [continue/abort]`
The `--mode` flag lets you specify what to do when encountering a duplicate dashboard, question, or any Admin Panel settings that already set (again, except for permissions and user settings, which are not currently included in data dumps). It can either `skip` that item and do nothing to it, or `update` it with the version being loaded. The default is `skip`.
The `--on-error` flag allows you to specify whether the load process should keep going or stop when there's an error. The default is `continue`. Note that `abort` won't undo any successful artifact loads that happened before an error was encountered.
Both of these flags are optional.
---
## That's it!
Still need help? Feel free to reach out to us at the support email address you were provided.
......@@ -7,3 +7,4 @@ The Enterprise Edition of Metabase provides added functionality and solutions fo
* [Customizing drill-through for charts and tables](customizing-drill-through.md)
* [Authenticating with SAML](authenticating-with-saml.md)
* [Authenticating with JWT](authenticating-with-jwt.md)
* [Copying contents of one Metabase instance to another (serialization)](serialization.md)
......@@ -21,28 +21,28 @@ When you need to share dashboards or pulses with others, we *strongly* recommend
## Asking questions and running queries
### Can I use SQL with Metabase?
[Yes](http://www.metabase.com/docs/latest/users-guide/04-asking-questions.html#using-sql).
[Yes](https://metabase.com/docs/latest/users-guide/04-asking-questions.html#using-sql).
### Do I need to know SQL to use Metabase?
[No](http://www.metabase.com/docs/latest/users-guide/04-asking-questions.html)
[No](https://metabase.com/docs/latest/users-guide/04-asking-questions.html)
### Does Metabase support SQL Joins?
Metabase does not expose a "Join" operator, but we do provide ways for non-SQL-proficient users to perform the tasks that joins are used for such as filtering or grouping by columns in other tables, etc.
For more info see our [blog post on the subject](http://www.metabase.com/blog/Joins)
For more info see our [blog post on the subject](https://metabase.com/blog/Joins)
### Why can't I do X in the Query Builder?
The primary audience of the GUI querying interface is a non-technical user who doesn't SQL. Advanced users can always [use SQL](http://www.metabase.com/docs/latest/users-guide/04-asking-questions.html#using-sql).
The primary audience of the GUI querying interface is a non-technical user who doesn't SQL. Advanced users can always [use SQL](https://metabase.com/docs/latest/users-guide/04-asking-questions.html#using-sql).
We're constantly trying to walk the line between putting more functionality into the GUI interface and creating a confusing mess. You can expect it to improve and change with time, but in the meantime, you can always lean on SQL directly for the complicated matters.
### Why can't I seem to use drill-through or question actions?
Metabase allows you to [click on your charts or tables to explore or zoom in](http://www.metabase.com/docs/latest/users-guide/03-basic-exploration.html), but these features don't currently work with SQL/native queries (this is because Metabase doesn't currently parse these kinds of queries). The same is true of the question actions menu in the bottom-right of the question detail page.
Metabase allows you to [click on your charts or tables to explore or zoom in](https://metabase.com/docs/latest/users-guide/03-basic-exploration.html), but these features don't currently work with SQL/native queries (this is because Metabase doesn't currently parse these kinds of queries). The same is true of the question actions menu in the bottom-right of the question detail page.
However, in [Metabase version 0.25 we introduced nested queries](http://www.metabase.com/blog/Metabase-0.25#nested-questions), a feature that lets you use the results of SQL/native queries as the starting table for GUI-based questions. This means you'll be able to use sophisticated SQL/native queries to create the exact segments you need, and you and your team will be able to use drill-through and actions if you create GUI-based questions from those segments.
However, in [Metabase version 0.25 we introduced nested queries](https://metabase.com/blog/Metabase-0.25#nested-questions), a feature that lets you use the results of SQL/native queries as the starting table for GUI-based questions. This means you'll be able to use sophisticated SQL/native queries to create the exact segments you need, and you and your team will be able to use drill-through and actions if you create GUI-based questions from those segments.
## Why are my field or table names showing up with weird spacing?
......@@ -132,18 +132,18 @@ Not exactly. Metabase provides access to data you have in an existing database y
Yes, to the extent that we are able to and have time.
If you're sure you've found a bug, please [open an issue](https://github.com/metabase/metabase/issues/new). Otherwise, try checking out the [troubleshooting guide](http://www.metabase.com/troubleshooting/) first to see if the answer to your problem is there.
If you're sure you've found a bug, please [open an issue](https://github.com/metabase/metabase/issues/new). Otherwise, try checking out the [troubleshooting guide](https://metabase.com/troubleshooting/) first to see if the answer to your problem is there.
If you're still having trouble, please start a conversation at our [discussion forum](http://discourse.metabase.com) and check out the other threads. Someone else might have experienced the same problem.
### Do you offer paid support?
We are experimenting with offering paid support to a limited number of companies. [Contact us](http://www.metabase.com/services/) if you want more information.
We are experimenting with offering paid support to a limited number of companies. [Contact us](https://metabase.com/services/) if you want more information.
## Embedding
### Can I embed charts or dashboards in another application?
Yes, Metabase offers two solutions for sharing charts and dashboards:
- [Public links](http://www.metabase.com/docs/latest/administration-guide/12-public-links.html) let you share or embed charts with simplicity.
- A powerful [application embedding](http://www.metabase.com/docs/latest/administration-guide/13-embedding.html) let you to embed and customize charts in your own web applications.
- [Public links](https://metabase.com/docs/latest/administration-guide/12-public-links.html) let you share or embed charts with simplicity.
- A powerful [application embedding](https://metabase.com/docs/latest/administration-guide/13-embedding.html) let you to embed and customize charts in your own web applications.
......@@ -4,7 +4,7 @@ To run the Metabase jar file you need to have Java installed on your system. Cur
### Download Metabase
If you haven't done so already the first thing you need to do is [Download Metabase](http://www.metabase.com/start/jar.html). Simply save the .jar file to a folder on your system where you wish to run Metabase.
If you haven't done so already the first thing you need to do is [Download Metabase](https://metabase.com/start/jar.html). Simply save the .jar file to a folder on your system where you wish to run Metabase.
### Verify Java is installed
......
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