diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 2af2d5f478df7ff13e0e72dd3005f8589ceb03bf..473a75ee799ce4cac4de7fdb0a410851616ffc2e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -27,6 +27,9 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Information about your Metabase Installation:** + +You can get this information by going to Admin -> Troubleshooting. + - Your browser and the version: (e.x. Chrome 52.1, Firefox 48.0, Safari 11.1, …) - Your operating system: (e.x. OS X 10.10, Windows 10.1809, Ubuntu 16.04, …) - Your databases: (e.x. MySQL, Postgres, MongoDB, …) diff --git a/dev/src/dev.clj b/dev/src/dev.clj index 646b379f7ef4a3d9550db101b65980372d72e45d..26e5802b6014886a27fb6e1834a696ece29f4bd2 100644 --- a/dev/src/dev.clj +++ b/dev/src/dev.clj @@ -11,7 +11,6 @@ [metabase.models.interface :as mi] [toucan.db :as tdb])) - (defn init! [] (mbc/init!)) diff --git a/frontend/src/metabase/admin/routes.jsx b/frontend/src/metabase/admin/routes.jsx index fe3ed2444ed9da48653403c0ba92bc71d302f283..de12af17430425c0b32dd9b623fa0b1cfb4ce3db 100644 --- a/frontend/src/metabase/admin/routes.jsx +++ b/frontend/src/metabase/admin/routes.jsx @@ -34,6 +34,7 @@ import TaskModal from "metabase/admin/tasks/containers/TaskModal"; import JobInfoApp from "metabase/admin/tasks/containers/JobInfoApp"; import JobTriggersModal from "metabase/admin/tasks/containers/JobTriggersModal"; import Logs from "metabase/admin/tasks/containers/Logs"; +import Help from "metabase/admin/tasks/containers/Help"; // People import PeopleListingApp from "metabase/admin/people/containers/PeopleListingApp"; @@ -109,7 +110,8 @@ const getRoutes = (store, IsAdmin) => ( title={t`Troubleshooting`} component={TroubleshootingApp} > - <IndexRedirect to="tasks" /> + <IndexRedirect to="help" /> + <Route path="help" component={Help} /> <Route path="tasks" component={TasksApp}> <ModalRoute path=":taskId" modal={TaskModal} /> </Route> diff --git a/frontend/src/metabase/admin/tasks/containers/Help.jsx b/frontend/src/metabase/admin/tasks/containers/Help.jsx new file mode 100644 index 0000000000000000000000000000000000000000..0f79a00d68c7ba235cee70d1a6d062783daba9d6 --- /dev/null +++ b/frontend/src/metabase/admin/tasks/containers/Help.jsx @@ -0,0 +1,132 @@ +import React, { Component } from "react"; +import { t } from "ttag"; +import _ from "underscore"; + +import { Box } from "grid-styled"; +import AdminHeader from "metabase/components/AdminHeader"; +import Code from "metabase/components/Code"; +import CopyButton from "metabase/components/CopyButton"; +import ExternalLink from "metabase/components/ExternalLink"; + +import { UtilApi } from "metabase/services"; +import MetabaseSettings from "metabase/lib/settings"; + +function navigatorInfo() { + return _.pick(navigator, "language", "platform", "userAgent", "vendor"); +} + +const template = `**Describe the bug** +A clear and concise description of what the bug is. + +**Logs** +Please include javascript console and server logs around the time this bug occurred. For information about how to get these, consult our [bug troubleshooting guide](https://metabase.com/docs/latest/troubleshooting-guide/bugs.html) + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Severity** +How severe an issue is this bug to you? Is this annoying, blocking some users, blocking an upgrade or blocking your usage of Metabase entirely? +Note: the more honest and specific you are here the more we will take you seriously. + +**Additional context** +Add any other context about the problem here. + +**Metabase Diagnostic Info** +`; + +function githubIssueLink(bugReportDetails) { + return ( + "https://github.com/metabase/metabase/issues/new?title=&labels=Type:Bug&body=" + + encodeURIComponent(template + "\n```json\n" + bugReportDetails + "\n```") + ); +} + +function discourseLink(bugReportDetails) { + return ( + "http://discourse.metabase.com/new-topic?category_id=7&body=" + + encodeURIComponent("```json\n" + bugReportDetails + "\n```") + ); +} + +const HelpLink = ({ title, description, link }) => ( + <li className="mb2"> + <ExternalLink + className="bordered border-brand-hover rounded transition-border flex p2 no-decoration" + href={link} + > + <div> + <h3 className="text-brand">{title}</h3> + <p className="m0 mt1">{description}</p> + </div> + </ExternalLink> + </li> +); + +const InfoBlock = ({ children }) => ( + <Box p={2} className="bordered rounded bg-light relative"> + <Box m={2} className="absolute top right text-brand-hover cursor-pointer"> + <CopyButton value={children} /> + </Box> + <Code>{children}</Code> + </Box> +); + +export default class Help extends Component { + state = { + details: { "browser-info": navigatorInfo() }, + }; + + async fetchDetails() { + const details = await UtilApi.bug_report_details(); + this.setState({ details: { ...this.state.details, ...details } }); + } + + componentWillMount() { + this.fetchDetails(); + } + + render() { + const { details } = this.state; + const detailString = JSON.stringify(details, null, 2); + return ( + <Box p={3}> + <AdminHeader title={t`Help`} className="mb2" /> + <Box my={2} style={{ maxWidth: "468px" }}> + <ol> + <HelpLink + title="Metabase Documentation" + description="Includes a troubleshooting guide" + link={MetabaseSettings.docsUrl()} + /> + <HelpLink + title="Post on the Metabase support forum" + description="A community forum for all things Metabase" + link={discourseLink(detailString)} + /> + <HelpLink + title="File a bug report" + description="Create a GitHub issue (includes the diagnostic info below)" + link={githubIssueLink(detailString)} + /> + </ol> + </Box> + + <Box my={2}> + <AdminHeader title={t`Diagnostic Info`} className="mb2" /> + <p>Please include these details in support requests. Thank you!</p> + <InfoBlock>{detailString}</InfoBlock> + </Box> + </Box> + ); + } +} diff --git a/frontend/src/metabase/admin/tasks/containers/TroubleshootingApp.jsx b/frontend/src/metabase/admin/tasks/containers/TroubleshootingApp.jsx index 67a16d84e4f3615b757844991085ec43427f4b3d..5c6365b8d160f4b0fb5291f025914a55d9a86837 100644 --- a/frontend/src/metabase/admin/tasks/containers/TroubleshootingApp.jsx +++ b/frontend/src/metabase/admin/tasks/containers/TroubleshootingApp.jsx @@ -18,6 +18,10 @@ export default class TroubleshootingApp extends Component { <AdminLayout sidebar={ <LeftNavPane> + <LeftNavPaneItem + name={t`Help`} + path="/admin/troubleshooting/help" + /> <LeftNavPaneItem name={t`Tasks`} path="/admin/troubleshooting/tasks" diff --git a/frontend/src/metabase/services.js b/frontend/src/metabase/services.js index f4413625e19c0ee972c761b0b2d439bb38f2b816..f91efd2d289e2c0513c486aa68185800458ea522 100644 --- a/frontend/src/metabase/services.js +++ b/frontend/src/metabase/services.js @@ -309,6 +309,7 @@ export const UtilApi = { password_check: POST("/api/util/password_check"), random_token: GET("/api/util/random_token"), logs: GET("/api/util/logs"), + bug_report_details: GET("/api/util/bug_report_details"), }; export const GeoJSONApi = { diff --git a/src/metabase/api/util.clj b/src/metabase/api/util.clj index 6f8c6c14df3615ae48202b91e4b811fe83067039..2270e7428f3899fd60a892567c6aa97d7a1e2ca0 100644 --- a/src/metabase/api/util.clj +++ b/src/metabase/api/util.clj @@ -3,8 +3,10 @@ page tasks." (:require [compojure.core :refer [GET POST]] [crypto.random :as crypto-random] + [metabase + [logger :as logger] + [troubleshooting :as troubleshooting]] [metabase.api.common :as api] - [metabase.logger :as logger] [metabase.util [schema :as su] [stats :as stats]])) @@ -34,5 +36,10 @@ [] {:token (crypto-random/hex 32)}) +(api/defendpoint GET "/bug_report_details" + [] + (api/check-superuser) + {:system-info (troubleshooting/system-info) + :metabase-info (troubleshooting/metabase-info)}) (api/define-routes) diff --git a/src/metabase/core.clj b/src/metabase/core.clj index 69558580d562efab1fd1924bfa52cd91978a4f74..e4b29a21cdb38a2a4dfa3adad2d9294a75945bbe 100644 --- a/src/metabase/core.clj +++ b/src/metabase/core.clj @@ -13,6 +13,7 @@ [server :as server] [setup :as setup] [task :as task] + [troubleshooting :as troubleshooting] [util :as u]] [metabase.core.initialization-status :as init-status] [metabase.driver.util :as driver.u] @@ -56,7 +57,7 @@ "General application initialization function which should be run once at application startup." [] (log/info (trs "Starting Metabase version {0} ..." config/mb-version-string)) - (log/info (trs "System timezone is ''{0}'' ..." (System/getProperty "user.timezone"))) + (log/info (trs "System info:\n {0}" (u/pprint-to-str (troubleshooting/system-info)))) (init-status/set-progress! 0.1) ;; First of all, lets register a shutdown hook that will tidy things up for us on app exit diff --git a/src/metabase/troubleshooting.clj b/src/metabase/troubleshooting.clj new file mode 100644 index 0000000000000000000000000000000000000000..c6a30838e46c2940399031a48f25509946d082b6 --- /dev/null +++ b/src/metabase/troubleshooting.clj @@ -0,0 +1,33 @@ +(ns metabase.troubleshooting + (:require [metabase + [config :as mc] + [db :as mdb]] + [metabase.models.setting :as setting] + [metabase.util.stats :as mus] + [toucan.db :as tdb])) + +(defn system-info + "System info we ask for for bug reports" + [] + (into (sorted-map) + (select-keys (System/getProperties) ["java.runtime.name" + "java.runtime.version" + "java.vendor" + "java.vendor.url" + "java.version" + "java.vm.name" + "java.vm.version" + "os.name" + "os.version" + "user.language" + "user.timezone"]))) + +(defn metabase-info + "Make it easy for the user to tell us what they're using" + [] + {:databases (->> (tdb/select 'Database) (map :engine) distinct) + :hosting-env (mus/environment-type) + :application-database (mdb/db-type) + :run-mode (mc/config-kw :mb-run-mode) + :version mc/mb-version-info + :settings {:report-timezone (setting/get :report-timezone)}}) diff --git a/src/metabase/util/stats.clj b/src/metabase/util/stats.clj index 2072d90d3807af719f23eebfb9a3046fce9962ba..a6162225d2dde9c88ca4c8105a5b6aba87459933 100644 --- a/src/metabase/util/stats.clj +++ b/src/metabase/util/stats.clj @@ -127,7 +127,7 @@ [] (:min (db/select-one [User [:%min.date_joined :min]]))) -(defn- environment-type +(defn environment-type "Figure out what we're running under" [] (cond