Skip to content
Snippets Groups Projects
Commit 2b18dbb7 authored by Simon Belak's avatar Simon Belak
Browse files

Merge branch 'master' of github.com:metabase/metabase into automagic-dashboards-nested-questions

parents b50e0b74 4bc4f71f
No related branches found
No related tags found
No related merge requests found
Showing
with 104 additions and 57 deletions
......@@ -39,7 +39,8 @@
"react/no-did-update-set-state": 0,
"react/no-find-dom-node": 0,
"flowtype/define-flow-type": 1,
"flowtype/use-flow-type": 1
"flowtype/use-flow-type": 1,
"no-var": 1
},
"globals": {
"pending": false
......
#!/usr/bin/env bash
set -eu
VERSION_PROPERTY_NAME="src_hash"
source-hash() {
# hash all the files that might change a backend-only uberjar build (for integration tests)
(
find src project.clj resources/sample-dataset.db.mv.db -type f -print0 | xargs -0 shasum ;
find resources -type f \( -iname \*.clj -o -iname \*.edn -o -iname \*.yaml -o -iname \*.properties \) -not -name "version.properties" -print0 | xargs -0 shasum ;
) | shasum | awk '{ print $1 }'
}
uberjar-hash() {
# java -jar target/uberjar/metabase.jar version | grep -oE 'source_hash [a-f0-9]+' | awk '{ print $2 }'
# pulling the version.properties directly from the jar is much faster
unzip -c target/uberjar/metabase.jar version.properties | grep "$VERSION_PROPERTY_NAME" | cut -f2 -d=
}
check-uberjar-hash() {
expected_hash=$(source-hash)
actual_hash=$(uberjar-hash)
if [ "$expected_hash" == "$actual_hash" ]; then
return 0
else
return 1
fi
}
build-uberjar-for-test() {
./bin/build version
echo "$VERSION_PROPERTY_NAME=$(source-hash)" >> resources/version.properties
./bin/build uberjar
}
if [ ! -f "target/uberjar/metabase.jar" ] || ! check-uberjar-hash; then
echo "Building uberjar for testing"
build-uberjar-for-test
else
echo "Uberjar already up to date for testing"
fi
......@@ -61,13 +61,13 @@ node-5() {
run_step lein with-profile +ci eastwood
run_step yarn run test-karma
run_step yarn run test-unit
run_step yarn run test-unit --coverage
report-frontend-coverage
}
node-6() {
run_step ./bin/build version sample-dataset uberjar
run_step ./bin/build-for-test
run_step check-uberjar-file-count
run_step yarn run test-integrated
run_step yarn run test-integrated-no-build
}
report() {
......
......@@ -14,7 +14,7 @@ function replaceReferences(str) {
if (process.argv.length !== 4) {
console.log(
"USAGE: build-translation-frontend-resource input.po output.json",
"USAGE: build-translation-frontend-resource input.po output.json"
);
process.exit(1);
}
......
......@@ -33,9 +33,9 @@ export default class DeleteDatabaseModal extends Component {
render() {
const { database } = this.props;
var formError;
let formError;
if (this.state.error) {
var errorMessage = t`Server error encountered`;
let errorMessage = t`Server error encountered`;
if (this.state.error.data && this.state.error.data.message) {
errorMessage = this.state.error.data.message;
} else {
......
......@@ -31,11 +31,11 @@ export default class MetadataHeader extends Component {
}
renderDbSelector() {
var database = this.props.databases.filter(
let database = this.props.databases.filter(
db => db.id === this.props.databaseId,
)[0];
if (database) {
var columns = [
let columns = [
{
selectedItem: database,
items: this.props.databases,
......@@ -46,7 +46,7 @@ export default class MetadataHeader extends Component {
},
},
];
var triggerElement = (
let triggerElement = (
<span className="text-bold cursor-pointer text-default">
{database.name}
<Icon className="ml1" name="chevrondown" size={8} />
......
......@@ -13,7 +13,7 @@ export default class MetadataSchema extends Component {
return false;
}
var fields = tableMetadata.fields.map(field => {
let fields = tableMetadata.fields.map(field => {
return (
<li key={field.id} className="px1 py2 flex border-bottom">
<div className="flex-full flex flex-column mr1">
......
......@@ -50,7 +50,7 @@ export default class MetadataTable extends Component {
}
renderVisibilityType(text, type, any) {
var classes = cx(
let classes = cx(
"mx1",
"text-bold",
"text-brand-hover",
......@@ -73,7 +73,7 @@ export default class MetadataTable extends Component {
}
renderVisibilityWidget() {
var subTypes;
let subTypes;
if (this.props.tableMetadata.visibility_type) {
subTypes = (
<span id="VisibilitySubTypes" className="border-left mx2">
......
......@@ -5,6 +5,7 @@ import ProgressBar from "metabase/components/ProgressBar.jsx";
import Icon from "metabase/components/Icon.jsx";
import { t } from "c-3po";
import { inflect } from "metabase/lib/formatting";
import { normal } from "metabase/lib/colors";
import _ from "underscore";
import cx from "classnames";
......@@ -37,30 +38,33 @@ export default class MetadataTableList extends Component {
}
render() {
var queryableTablesHeader, hiddenTablesHeader;
var queryableTables = [];
var hiddenTables = [];
let queryableTablesHeader, hiddenTablesHeader;
let queryableTables = [];
let hiddenTables = [];
if (this.props.tables) {
var tables = _.sortBy(this.props.tables, "display_name");
let tables = _.sortBy(this.props.tables, "display_name");
_.each(tables, table => {
var row = (
const selected = this.props.tableId === table.id;
let row = (
<li key={table.id}>
<a
className={cx("AdminList-item flex align-center no-decoration", {
selected: this.props.tableId === table.id,
selected,
})}
onClick={this.props.selectTable.bind(null, table)}
>
{table.display_name}
<ProgressBar
className="ProgressBar ProgressBar--mini flex-align-right"
percentage={table.metadataStrength}
/>
<span className="flex-align-right" style={{ width: 17 }}>
<ProgressBar
percentage={table.metadataStrength}
color={selected ? normal.grey2 : normal.grey1}
/>
</span>
</a>
</li>
);
var regex = this.state.searchRegex;
let regex = this.state.searchRegex;
if (
!regex ||
regex.test(table.display_name) ||
......
......@@ -77,12 +77,12 @@ export default class MetadataEditor extends Component {
}
render() {
var tableMetadata = this.props.databaseMetadata
let tableMetadata = this.props.databaseMetadata
? _.findWhere(this.props.databaseMetadata.tables, {
id: this.props.editingTable,
})
: null;
var content;
let content;
if (tableMetadata) {
if (this.state.isShowingSchema) {
content = <MetadataSchema tableMetadata={tableMetadata} />;
......
......@@ -125,7 +125,7 @@ export const fetchUsers = createThunkAction(FETCH_USERS, function() {
return async function(dispatch, getState) {
let users = await UserApi.list();
for (var u of users) {
for (let u of users) {
u.date_joined = u.date_joined ? moment(u.date_joined) : null;
u.last_login = u.last_login ? moment(u.last_login) : null;
}
......
......@@ -129,7 +129,7 @@ export default class Calendar extends Component {
}
renderWeeks(current) {
var weeks = [],
let weeks = [],
done = false,
date = moment(current)
.startOf("month")
......
......@@ -22,15 +22,15 @@ export default class ColumnarSelector extends Component {
? column.disabledOptionIds.includes(item.id)
: false;
var columns = this.props.columns.map((column, columnIndex) => {
var sectionElements;
let columns = this.props.columns.map((column, columnIndex) => {
let sectionElements;
if (column) {
var lastColumn = columnIndex === this.props.columns.length - 1;
var sections = column.sections || [column];
let lastColumn = columnIndex === this.props.columns.length - 1;
let sections = column.sections || [column];
sectionElements = sections.map((section, sectionIndex) => {
var title = section.title;
var items = section.items.map((item, rowIndex) => {
var itemClasses = cx({
let title = section.title;
let items = section.items.map((item, rowIndex) => {
let itemClasses = cx({
"ColumnarSelector-row": true,
"ColumnarSelector-row--selected": isItemSelected(item, column),
"ColumnarSelector-row--disabled": isItemDisabled(item, column),
......@@ -38,9 +38,9 @@ export default class ColumnarSelector extends Component {
"no-decoration": true,
"cursor-default": isItemDisabled(item, column),
});
var checkIcon = lastColumn ? <Icon name="check" size={14} /> : null;
var descriptionElement;
var description =
let checkIcon = lastColumn ? <Icon name="check" size={14} /> : null;
let descriptionElement;
let description =
column.itemDescriptionFn && column.itemDescriptionFn(item);
if (description) {
descriptionElement = (
......@@ -67,7 +67,7 @@ export default class ColumnarSelector extends Component {
</li>
);
});
var titleElement;
let titleElement;
if (title) {
titleElement = (
<div className="ColumnarSelector-title">{title}</div>
......
......@@ -35,17 +35,17 @@ export default class CreateDashboardModal extends Component {
createNewDash(event) {
event.preventDefault();
var name = this.state.name && this.state.name.trim();
var description = this.state.description && this.state.description.trim();
let name = this.state.name && this.state.name.trim();
let description = this.state.description && this.state.description.trim();
// populate a new Dash object
var newDash = {
let newDash = {
name: name && name.length > 0 ? name : null,
description: description && description.length > 0 ? description : null,
};
// create a new dashboard
var component = this;
let component = this;
this.props.createDashboardFn(newDash).then(null, function(error) {
component.setState({
errors: error,
......@@ -54,9 +54,9 @@ export default class CreateDashboardModal extends Component {
}
render() {
var formError;
let formError;
if (this.state.errors) {
var errorMessage = t`Server error encountered`;
let errorMessage = t`Server error encountered`;
if (this.state.errors.data && this.state.errors.data.message) {
errorMessage = this.state.errors.data.message;
}
......@@ -65,9 +65,9 @@ export default class CreateDashboardModal extends Component {
formError = <span className="text-error px2">{errorMessage}</span>;
}
var name = this.state.name && this.state.name.trim();
let name = this.state.name && this.state.name.trim();
var formReady = name !== null && name !== "";
let formReady = name !== null && name !== "";
return (
<ModalContent
......
......@@ -252,7 +252,7 @@ export default class DatabaseDetailsForm extends Component {
} else if (field.name === "client-id" && CREDENTIALS_URL_PREFIXES[engine]) {
let { details } = this.state;
let projectID = details && details["project-id"];
var credentialsURLLink;
let credentialsURLLink;
// if (projectID) {
let credentialsURL = CREDENTIALS_URL_PREFIXES[engine] + (projectID || "");
credentialsURLLink = (
......@@ -279,7 +279,7 @@ export default class DatabaseDetailsForm extends Component {
} else if (field.name === "auth-code" && AUTH_URL_PREFIXES[engine]) {
let { details } = this.state;
const clientID = details && details["client-id"];
var authURLLink;
let authURLLink;
if (clientID) {
let authURL = AUTH_URL_PREFIXES[engine] + clientID;
authURLLink = (
......
......@@ -75,7 +75,7 @@ export default class Header extends Component {
}
render() {
var titleAndDescription;
let titleAndDescription;
if (this.props.isEditingInfo) {
titleAndDescription = (
<div className="Header-title flex flex-column flex-full bordered rounded my1">
......@@ -112,7 +112,7 @@ export default class Header extends Component {
}
}
var attribution;
let attribution;
if (this.props.item && this.props.item.creator) {
attribution = (
<div className="Header-attribution">
......@@ -121,7 +121,7 @@ export default class Header extends Component {
);
}
var headerButtons = this.props.headerButtons.map(
let headerButtons = this.props.headerButtons.map(
(section, sectionIndex) => {
return (
section &&
......
......@@ -8,7 +8,7 @@ import ModalContent from "metabase/components/ModalContent.jsx";
import moment from "moment";
function formatDate(date) {
var m = moment(date);
let m = moment(date);
if (m.isSame(moment(), "day")) {
return t`Today, ` + m.format("h:mm a");
} else if (m.isSame(moment().subtract(1, "day"), "day")) {
......@@ -74,7 +74,7 @@ export default class HistoryModal extends Component {
}
render() {
var { revisions } = this.props;
let { revisions } = this.props;
return (
<ModalContent
title={t`Revision history`}
......
......@@ -11,7 +11,7 @@ export default class LoadingSpinner extends Component {
};
render() {
var { size, borderWidth, className, spinnerClassName } = this.props;
let { size, borderWidth, className, spinnerClassName } = this.props;
return (
<div className={className}>
<div
......
......@@ -35,7 +35,7 @@ export default class NewsletterForm extends Component {
subscribeUser(e) {
e.preventDefault();
var formData = new FormData();
let formData = new FormData();
formData.append("EMAIL", ReactDOM.findDOMNode(this.refs.email).value);
formData.append("b_869fec0e4689e8fd1db91e795_b9664113a8", "");
......
......@@ -44,7 +44,7 @@ export default class OnClickOutsideWrapper extends Component {
// remove from the stack after a delay, if it is removed through some other
// means this will happen too early causing parent modal to close
setTimeout(() => {
var index = popoverStack.indexOf(this);
let index = popoverStack.indexOf(this);
if (index >= 0) {
popoverStack.splice(index, 1);
}
......
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