mirror of https://github.com/Budibase/budibase.git
36 changed files with 213 additions and 190 deletions
@ -1,25 +1,71 @@ |
|||||
import * as Sentry from "@sentry/browser" |
import * as Sentry from "@sentry/browser" |
||||
import posthog from "posthog-js" |
import posthog from "posthog-js" |
||||
|
import api from "builderStore/api" |
||||
|
|
||||
function activate() { |
let analyticsEnabled |
||||
Sentry.init({ dsn: process.env.SENTRY_DSN }) |
const posthogConfigured = process.env.POSTHOG_TOKEN && process.env.POSTHOG_URL |
||||
if (!process.env.POSTHOG_TOKEN) return |
const sentryConfigured = process.env.SENTRY_DSN |
||||
posthog.init(process.env.POSTHOG_TOKEN, { |
|
||||
api_host: process.env.POSTHOG_URL, |
async function activate() { |
||||
}) |
if (analyticsEnabled === undefined) { |
||||
|
// only the server knows the true NODE_ENV
|
||||
|
// this was an issue as NODE_ENV = 'cypress' on the server,
|
||||
|
// but 'production' on the client
|
||||
|
const response = await api.get("/api/analytics") |
||||
|
analyticsEnabled = (await response.json()) === true |
||||
|
} |
||||
|
if (!analyticsEnabled) return |
||||
|
if (sentryConfigured) Sentry.init({ dsn: process.env.SENTRY_DSN }) |
||||
|
if (posthogConfigured) { |
||||
|
posthog.init(process.env.POSTHOG_TOKEN, { |
||||
|
api_host: process.env.POSTHOG_URL, |
||||
|
}) |
||||
|
posthog.set_config({ persistence: "cookie" }) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function identify(id) { |
||||
|
if (!analyticsEnabled || !id) return |
||||
|
if (posthogConfigured) posthog.identify(id) |
||||
|
if (sentryConfigured) |
||||
|
Sentry.configureScope(scope => { |
||||
|
scope.setUser({ id: id }) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
async function identifyByApiKey(apiKey) { |
||||
|
if (!analyticsEnabled) return true |
||||
|
const response = await fetch( |
||||
|
`https://03gaine137.execute-api.eu-west-1.amazonaws.com/prod/account/id?api_key=${apiKey.trim()}` |
||||
|
) |
||||
|
|
||||
|
if (response.status === 200) { |
||||
|
const id = await response.json() |
||||
|
|
||||
|
await api.put("/api/keys/userId", { value: id }) |
||||
|
identify(id) |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
return false |
||||
} |
} |
||||
|
|
||||
function captureException(err) { |
function captureException(err) { |
||||
|
if (!analyticsEnabled) return |
||||
Sentry.captureException(err) |
Sentry.captureException(err) |
||||
|
captureEvent("Error", { error: err.message ? err.message : err }) |
||||
} |
} |
||||
|
|
||||
function captureEvent(event) { |
function captureEvent(eventName, props = {}) { |
||||
if (!process.env.POSTHOG_TOKEN) return |
if (!analyticsEnabled || !process.env.POSTHOG_TOKEN) return |
||||
posthog.capture(event) |
props.sourceApp = "builder" |
||||
|
posthog.capture(eventName, props) |
||||
} |
} |
||||
|
|
||||
export default { |
export default { |
||||
activate, |
activate, |
||||
|
identify, |
||||
|
identifyByApiKey, |
||||
captureException, |
captureException, |
||||
captureEvent, |
captureEvent, |
||||
} |
} |
||||
|
|||||
@ -1,139 +0,0 @@ |
|||||
<script> |
|
||||
import { Button, Select } from "@budibase/bbui" |
|
||||
import StateBindingCascader from "./StateBindingCascader.svelte" |
|
||||
import { find, map, keys, reduce, keyBy } from "lodash/fp" |
|
||||
import { pipe } from "components/common/core" |
|
||||
import { |
|
||||
EVENT_TYPE_MEMBER_NAME, |
|
||||
allHandlers, |
|
||||
} from "components/common/eventHandlers" |
|
||||
import { store } from "builderStore" |
|
||||
|
|
||||
export let handler |
|
||||
export let onCreate |
|
||||
export let onChanged |
|
||||
export let onRemoved |
|
||||
|
|
||||
export let index |
|
||||
export let newHandler |
|
||||
|
|
||||
let eventOptions |
|
||||
let handlerType |
|
||||
let parameters = [] |
|
||||
|
|
||||
$: eventOptions = allHandlers() |
|
||||
|
|
||||
$: { |
|
||||
if (handler) { |
|
||||
handlerType = handler[EVENT_TYPE_MEMBER_NAME] |
|
||||
parameters = Object.entries(handler.parameters).map(([name, value]) => ({ |
|
||||
name, |
|
||||
value, |
|
||||
})) |
|
||||
} else { |
|
||||
// Empty Handler |
|
||||
handlerType = "" |
|
||||
parameters = [] |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const handlerChanged = (type, params) => { |
|
||||
const handlerParams = {} |
|
||||
for (let param of params) { |
|
||||
handlerParams[param.name] = param.value |
|
||||
} |
|
||||
|
|
||||
const updatedHandler = { |
|
||||
[EVENT_TYPE_MEMBER_NAME]: type, |
|
||||
parameters: handlerParams, |
|
||||
} |
|
||||
|
|
||||
onChanged(updatedHandler, index) |
|
||||
} |
|
||||
|
|
||||
const handlerTypeChanged = e => { |
|
||||
const handlerType = eventOptions.find( |
|
||||
handler => handler.name === e.target.value |
|
||||
) |
|
||||
const defaultParams = handlerType.parameters.map(param => ({ |
|
||||
name: param, |
|
||||
value: "", |
|
||||
})) |
|
||||
|
|
||||
handlerChanged(handlerType.name, defaultParams) |
|
||||
} |
|
||||
|
|
||||
const onParameterChanged = index => e => { |
|
||||
const value = e.target ? e.target.value : e |
|
||||
const newParams = [...parameters] |
|
||||
newParams[index].value = value |
|
||||
handlerChanged(handlerType, newParams) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div class="type-selector-container {newHandler && 'new-handler'}"> |
|
||||
<div class="handler-controls"> |
|
||||
<div class="handler-option"> |
|
||||
<span>Action</span> |
|
||||
<Select value={handlerType} on:change={handlerTypeChanged}> |
|
||||
<option /> |
|
||||
{#each eventOptions as option} |
|
||||
<option value={option.name}>{option.name}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</div> |
|
||||
{#if parameters} |
|
||||
<br /> |
|
||||
{#each parameters as parameter, idx} |
|
||||
<StateBindingCascader on:change={onParameterChanged(idx)} {parameter} /> |
|
||||
{/each} |
|
||||
{/if} |
|
||||
{#if parameters.length > 0} |
|
||||
<div class="button-container"> |
|
||||
{#if newHandler} |
|
||||
<Button primary thin on:click={onCreate}>Add Action</Button> |
|
||||
{:else} |
|
||||
<Button outline thin on:click={onRemoved}>Remove Action</Button> |
|
||||
{/if} |
|
||||
</div> |
|
||||
{/if} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.type-selector-container { |
|
||||
display: grid; |
|
||||
grid-gap: 20px; |
|
||||
width: 100%; |
|
||||
background: rgba(223, 223, 223, 0.5); |
|
||||
border: 1px solid #dfdfdf; |
|
||||
margin-bottom: 18px; |
|
||||
} |
|
||||
|
|
||||
.handler-option { |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
} |
|
||||
|
|
||||
.new-handler { |
|
||||
background: #fff; |
|
||||
} |
|
||||
|
|
||||
.handler-controls { |
|
||||
display: grid; |
|
||||
grid-template-columns: 1fr; |
|
||||
grid-gap: 20px; |
|
||||
padding: 22px; |
|
||||
} |
|
||||
|
|
||||
.button-container { |
|
||||
display: grid; |
|
||||
justify-items: end; |
|
||||
} |
|
||||
|
|
||||
span { |
|
||||
font-size: 18px; |
|
||||
margin-bottom: 10px; |
|
||||
font-weight: 500; |
|
||||
} |
|
||||
</style> |
|
||||
@ -0,0 +1,3 @@ |
|||||
|
exports.isEnabled = async function(ctx) { |
||||
|
ctx.body = JSON.stringify(process.env.ENABLE_ANALYTICS === "true") |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
const Router = require("@koa/router") |
||||
|
const authorized = require("../../middleware/authorized") |
||||
|
const { BUILDER } = require("../../utilities/accessLevels") |
||||
|
const controller = require("../controllers/analytics") |
||||
|
|
||||
|
const router = Router() |
||||
|
|
||||
|
router.get("/api/analytics", authorized(BUILDER), controller.isEnabled) |
||||
|
|
||||
|
module.exports = router |
||||
Loading…
Reference in new issue