Skip to content

Commit

Permalink
Remove last bits of Angular 😻
Browse files Browse the repository at this point in the history
  • Loading branch information
tlrobinson committed Oct 19, 2016
1 parent f5d3116 commit 7bc911e
Show file tree
Hide file tree
Showing 18 changed files with 680 additions and 851 deletions.
1 change: 0 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"flow-vars/use-flow-type": 1
},
"globals": {
"angular": false
},
"env": {
"browser": true,
Expand Down
1 change: 0 additions & 1 deletion frontend/interfaces/angular.js

This file was deleted.

3 changes: 1 addition & 2 deletions frontend/src/metabase/admin/datamodel/datamodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,8 @@ export const updateField = createThunkAction("UPDATE_FIELD", function(field) {
let slimField = { ...field };
slimField = _.omit(slimField, "operators_lookup", "valid_operators", "values");

// update the field and strip out angular junk
// update the field
let updatedField = await MetabaseApi.field_update(slimField);
_.each(updatedField, (value, key) => { if (key.charAt(0) !== "$") { updatedField[key] = value } });

// refresh idfields
let table = _.findWhere(editingDatabase.tables, {id: updatedField.table_id});
Expand Down
33 changes: 10 additions & 23 deletions frontend/src/metabase/app.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
/* @flow weak */

// angular:
import "./services";

angular
.module('metabase', ['ipCookie', 'metabase.controllers'])
.run([function() {}])

angular
.module('metabase.controllers', ['metabase.services'])
.controller('Metabase', [function() {}]);

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
Expand All @@ -19,6 +8,8 @@ import { push } from "react-router-redux";
import MetabaseAnalytics, { registerAnalyticsClickListener } from "metabase/lib/analytics";
import MetabaseSettings from "metabase/lib/settings";

import api from "metabase/lib/api";

import { getRoutes } from "./routes.jsx";
import { getStore } from './store'

Expand All @@ -27,10 +18,6 @@ import { refreshSiteSettings } from "metabase/redux/settings";
import { Router, browserHistory } from "react-router";
import { syncHistoryWithStore } from 'react-router-redux'

function getRootScope() {
return angular.element(document.body).injector().get("$rootScope");
}

function init() {
const store = getStore(browserHistory);
const routes = getRoutes(store);
Expand Down Expand Up @@ -58,21 +45,21 @@ function init() {
window['ga-disable-' + MetabaseSettings.get('ga_code')] = MetabaseSettings.isTrackingEnabled() ? null : true;
});

// $http interceptor received a 401 response
getRootScope().$on("event:auth-loginRequired", function() {
// received a 401 response
api.on("401", () => {
store.dispatch(push("/auth/login"));
});

// we shouldn't redirect these URLs because we want to handle them differently
let WHITELIST_FORBIDDEN_URLS = [
/api\/card\/\d+\/query$/,
/api\/database\/\d+\/metadata$/
]
// $http interceptor received a 403 response
getRootScope().$on("event:auth-forbidden", function(event, data) {
if (data && data.config && data.config.url) {
for (const url of WHITELIST_FORBIDDEN_URLS) {
if (url.test(data.config.url)) {
];
// received a 403 response
api.on("403", (url) => {
if (url) {
for (const regex of WHITELIST_FORBIDDEN_URLS) {
if (regex.test(url)) {
return;
}
}
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/metabase/dashboard/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import MetabaseAnalytics from "metabase/lib/analytics";
import { getPositionForNewDashCard } from "metabase/lib/dashboard_grid";
import { applyParameters } from "metabase/meta/Card";
import { fetchDatabaseMetadata } from "metabase/redux/metadata";
import Utils from "metabase/lib/utils";

import type { Dashboard, DashCard, DashCardId } from "metabase/meta/types/Dashboard";
import type { Card, CardId } from "metabase/meta/types/Card";
Expand Down Expand Up @@ -165,7 +166,7 @@ export const fetchCardData = createThunkAction(FETCH_CARD_DATA, function(card, d
// if reload not set, check to see if the last result has the same query dict and return that
const lastResult = i.getIn(dashcardData, [dashcard.id, card.id]);
// "constraints" is added by the backend, remove it when comparing
if (lastResult && angular.equals(_.omit(lastResult.json_query, "constraints"), datasetQuery)) {
if (lastResult && Utils.equals(_.omit(lastResult.json_query, "constraints"), datasetQuery)) {
return {
dashcard_id: dashcard.id,
card_id: card.id,
Expand All @@ -189,7 +190,7 @@ export const fetchCardData = createThunkAction(FETCH_CARD_DATA, function(card, d
}, DATASET_SLOW_TIMEOUT);

// make the actual request
result = await fetchDataOrError(CardApi.query({cardID: card.id, parameters: datasetQuery.parameters}));
result = await fetchDataOrError(CardApi.query({cardId: card.id, parameters: datasetQuery.parameters}));

clearTimeout(slowCardTimer);

Expand Down
83 changes: 83 additions & 0 deletions frontend/src/metabase/lib/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* @flow */

import querystring from "querystring";

import EventEmitter from "events";

let events = new EventEmitter();

function makeMethod(method: string, hasBody: boolean = false) {
return function(
urlTemplate: string,
params: { [key:string]: any } = {}
) {
return function(
data: { [key:string]: any },
options: { [key:string]: any } = {}
): Promise<any> {
let url = urlTemplate;
data = { ...data };
for (let tag of (url.match(/:\w+/g) || [])) {
let value = data[tag.slice(1)];
if (value === undefined) {
console.warn("Warning: calling", method, "without", tag);
value = "";
}
url = url.replace(tag, encodeURIComponent(data[tag.slice(1)]))
delete data[tag.slice(1)];
}

let headers: { [key:string]: string } = {
"Accept": "application/json",
};

let body;
if (hasBody) {
headers["Content-Type"] = "application/json";
body = JSON.stringify(data);
} else {
let qs = querystring.stringify(data);
if (qs) {
url += (url.indexOf("?") >= 0 ? "&" : "?") + qs;
}
}

return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(method, url);
for (let headerName in headers) {
xhr.setRequestHeader(headerName, headers[headerName])
}
xhr.onreadystatechange = function() {
// $FlowFixMe
if (xhr.readyState === XMLHttpRequest.DONE) {
let body = xhr.responseText;
try { body = JSON.parse(body); } catch (e) {}
if (xhr.status >= 200 && xhr.status <= 299) {
resolve(body);
} else {
reject({
status: xhr.status,
data: body
});
}
events.emit(xhr.status, url);
}
}
xhr.send(body);

if (options.cancelled) {
options.cancelled.then(() => xhr.abort());
}
})

}
}
}

export const GET = makeMethod("GET");
export const DELETE = makeMethod("DELETE");
export const POST = makeMethod("POST", true);
export const PUT = makeMethod("PUT", true);

export default events;
9 changes: 3 additions & 6 deletions frontend/src/metabase/lib/card.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import _ from "underscore";
import Query from "metabase/lib/query";
import Utils from "metabase/lib/utils";
import { createQuery } from "metabase/lib/query";
import { AngularResourceProxy } from "metabase/lib/redux";

Expand Down Expand Up @@ -27,11 +28,8 @@ export function startNewCard(type, databaseId, tableId) {
// load a card either by ID or from a base64 serialization. if both are present then they are merged, which the serialized version taking precedence
export async function loadCard(cardId) {
try {
let card = card = await Card.get({ "cardId": cardId });

// strip off angular $xyz stuff
let card = await Card.get({ "cardId": cardId });
return card && cleanCopyCard(card);

} catch (error) {
console.log("error loading card", error);
throw error;
Expand Down Expand Up @@ -65,8 +63,7 @@ export function isCardDirty(card, originalCard) {
}

export function serializeCardForUrl(card) {
// console.log(JSON.stringify(card, null, ' '));
var dataset_query = angular.copy(card.dataset_query);
var dataset_query = Utils.copy(card.dataset_query);
if (dataset_query.query) {
dataset_query.query = Query.cleanQuery(dataset_query.query);
}
Expand Down
13 changes: 4 additions & 9 deletions frontend/src/metabase/lib/cookies.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@

import { clearGoogleAuthCredentials } from "metabase/lib/auth";

// import Cookies from "js-cookie";
import Cookies from "js-cookie";

export const METABASE_SESSION_COOKIE = 'metabase.SESSION_ID';

// Handles management of Metabase cookie work
var MetabaseCookies = {
// set the session cookie. if sessionId is null, clears the cookie
setSessionCookie: function(sessionId) {
let ipCookie = angular.element(document.body).injector().get("ipCookie");

const options = {
path: '/',
expires: 14,
Expand All @@ -20,15 +18,12 @@ var MetabaseCookies = {
try {
if (sessionId) {
// set a session cookie
// Cookies.set(METABASE_SESSION_COOKIE, sessionId);
ipCookie(METABASE_SESSION_COOKIE, sessionId, options);
Cookies.set(METABASE_SESSION_COOKIE, sessionId, options);
} else {
// sessionId = Cookies.get(METABASE_SESSION_COOKIE);
sessionId = ipCookie(METABASE_SESSION_COOKIE);
sessionId = Cookies.get(METABASE_SESSION_COOKIE);

// delete the current session cookie and Google Auth creds
// Cookies.remove(METABASE_SESSION_COOKIE);
ipCookie.remove(METABASE_SESSION_COOKIE);
Cookies.remove(METABASE_SESSION_COOKIE);
clearGoogleAuthCredentials();

return sessionId;
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/metabase/lib/promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,12 @@ export function timeout(promise, duration, error) {
export function delay(duration) {
return new Promise((resolve, reject) => setTimeout(resolve, duration));
}

export function defer() {
let deferrred = {}
deferrred.promise = new Promise((resolve, reject) => {
deferrred.resolve = resolve;
deferrred.reject = reject;
});
return deferrred;
}
3 changes: 2 additions & 1 deletion frontend/src/metabase/lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from "react";
import inflection from "inflection";
import _ from "underscore";

import Utils from "metabase/lib/utils";
import { getOperators } from "metabase/lib/schema_metadata";
import { createLookupByProperty } from "metabase/lib/table";
import { isFK, TYPE } from "metabase/lib/types";
Expand All @@ -29,7 +30,7 @@ export const NEW_QUERY_TEMPLATES = {
};

export function createQuery(type = "query", databaseId, tableId) {
let dataset_query = angular.copy(NEW_QUERY_TEMPLATES[type]);
let dataset_query = Utils.copy(NEW_QUERY_TEMPLATES[type]);

if (databaseId) {
dataset_query.database = databaseId;
Expand Down
14 changes: 3 additions & 11 deletions frontend/src/metabase/lib/redux.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,11 @@ export const createStore = compose(
window.devToolsExtension ? window.devToolsExtension() : f => f
)(originalCreateStore);

import * as services from "metabase/services";

// HACK: just use our Angular resources for now
export function AngularResourceProxy(serviceName, methods) {
methods.forEach((methodName) => {
this[methodName] = function(...args) {
let service = angular.element(document.body).injector().get(serviceName);
return service[methodName](...args).$promise;
}
});
}

export function angularPromise() {
let $q = angular.element(document.body).injector().get("$q");
return $q.defer();
return services[serviceName];
}

// similar to createAction but accepts a (redux-thunk style) thunk and dispatches based on whether
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/metabase/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ var MetabaseUtils = {
validEmail: function(email) {
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
},

equals: function(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
},

copy: function(a) {
return JSON.parse(JSON.stringify(a));
}
}

Expand Down
13 changes: 7 additions & 6 deletions frontend/src/metabase/query_builder/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import _ from "underscore";
import i from "icepick";
import moment from "moment";

import { AngularResourceProxy, angularPromise, createThunkAction } from "metabase/lib/redux";
import { AngularResourceProxy, createThunkAction } from "metabase/lib/redux";
import { push, replace } from "react-router-redux";

import MetabaseAnalytics from "metabase/lib/analytics";
Expand All @@ -16,6 +16,7 @@ import { createQuery } from "metabase/lib/query";
import { loadTableAndForeignKeys } from "metabase/lib/table";
import { isPK, isFK } from "metabase/lib/types";
import Utils from "metabase/lib/utils";
import { defer } from "metabase/lib/promise";
import { applyParameters } from "metabase/meta/Card";

import { getParameters, getNativeDatabases } from "./selectors";
Expand All @@ -34,7 +35,7 @@ export const popState = createThunkAction(POP_STATE, (location) =>
async (dispatch, getState) => {
const { card } = getState().qb;
if (location.state && location.state.card) {
if (!angular.equals(card, location.state.card)) {
if (!Utils.equals(card, location.state.card)) {
dispatch(setCardAndRun(location.state.card, false));
dispatch(setCurrentState(location.state));
}
Expand All @@ -57,7 +58,7 @@ export const updateUrl = createThunkAction(UPDATE_URL, (card, isDirty = false, r

const { currentState } = getState().qb;

if (angular.equals(currentState, newState)) {
if (Utils.equals(currentState, newState)) {
return;
}

Expand Down Expand Up @@ -779,7 +780,7 @@ export const runQuery = createThunkAction(RUN_QUERY, (card, shouldUpdateUrl = tr
dispatch(updateUrl(card, cardIsDirty));
}

let cancelQueryDeferred = angularPromise();
let cancelQueryDeferred = defer();
const startTime = new Date();

// make our api call
Expand All @@ -792,9 +793,9 @@ export const runQuery = createThunkAction(RUN_QUERY, (card, shouldUpdateUrl = tr
}

if (card && card.id) {
CardAPI.query({ timeout: cancelQueryDeferred.promise }, { cardID: card.id, parameters: card.dataset_query.parameters }, onQuerySuccess, onQueryError);
CardAPI.query({ cardId: card.id, parameters: card.dataset_query.parameters }, { cancelled: cancelQueryDeferred.promise }).then(onQuerySuccess, onQueryError);
} else {
Metabase.dataset({ timeout: cancelQueryDeferred.promise }, card.dataset_query, onQuerySuccess, onQueryError);
Metabase.dataset(card.dataset_query, { cancelled: cancelQueryDeferred.promise }).then(onQuerySuccess, onQueryError);
}

MetabaseAnalytics.trackEvent("QueryBuilder", "Run Query", card.dataset_query.type);
Expand Down
Loading

0 comments on commit 7bc911e

Please sign in to comment.