Merge remote-tracking branch 'origin/develop' into feature/configurable-data-export
This commit is contained in:
commit
45b907cfde
|
@ -6,6 +6,8 @@ labels: bug
|
|||
assignees: ''
|
||||
|
||||
---
|
||||
**Checklist**
|
||||
- [ ] I have searched budibase discussions and github issues to check if my issue already exists
|
||||
|
||||
**Hosting**
|
||||
<!-- Delete as appropriate -->
|
||||
|
|
|
@ -20,8 +20,8 @@ spec:
|
|||
annotations:
|
||||
kompose.cmd: kompose convert
|
||||
kompose.version: 1.21.0 (992df58d8)
|
||||
{{ if .Values.globals.appServiceAnnotations }}
|
||||
{{ toYaml .Values.globals.appServiceAnnotations | indent 4 }}
|
||||
{{ if .Values.services.apps.annotations }}
|
||||
{{- toYaml .Values.services.apps.annotations | indent 8 -}}
|
||||
{{ end }}
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
|
|
|
@ -20,8 +20,8 @@ spec:
|
|||
annotations:
|
||||
kompose.cmd: kompose convert
|
||||
kompose.version: 1.21.0 (992df58d8)
|
||||
{{ if .Values.globals.proxyServiceAnnotations }}
|
||||
{{ toYaml .Values.globals.proxyServiceAnnotations | indent 4 }}
|
||||
{{ if .Values.services.proxy.annotations }}
|
||||
{{- toYaml .Values.services.proxy.annotations | indent 8 -}}
|
||||
{{ end }}
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
|
|
|
@ -21,8 +21,8 @@ spec:
|
|||
annotations:
|
||||
kompose.cmd: kompose convert
|
||||
kompose.version: 1.21.0 (992df58d8)
|
||||
{{ if .Values.globals.workerServiceAnnotations }}
|
||||
{{ toYaml .Values.globals.workerServiceAnnotations | indent 4 }}
|
||||
{{ if .Values.services.worker.annotations }}
|
||||
{{- toYaml .Values.services.worker.annotations | indent 8 -}}
|
||||
{{ end }}
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
|
|
|
@ -22,23 +22,6 @@ serviceAccount:
|
|||
|
||||
podAnnotations: {}
|
||||
|
||||
# appServiceAnnotations:
|
||||
# co.elastic.logs/multiline.type: pattern
|
||||
# co.elastic.logs/multiline.pattern: '^[[:space:]]'
|
||||
# co.elastic.logs/multiline.negate: false
|
||||
# co.elastic.logs/multiline.match: after
|
||||
|
||||
# workerServiceAnnotations:
|
||||
# co.elastic.logs/multiline.type: pattern
|
||||
# co.elastic.logs/multiline.pattern: '^[[:space:]]'
|
||||
# co.elastic.logs/multiline.negate: false
|
||||
# co.elastic.logs/multiline.match: after
|
||||
|
||||
# proxyServiceAnnotations:
|
||||
# co.elastic.logs/module: nginx
|
||||
# co.elastic.logs/fileset.stdout: access
|
||||
# co.elastic.logs/fileset.stderr: error
|
||||
|
||||
podSecurityContext:
|
||||
{}
|
||||
# fsGroup: 2000
|
||||
|
@ -141,6 +124,10 @@ services:
|
|||
minio: 'http://minio-service.{{ .Release.Namespace }}.svc.{{ .Values.services.dns }}:{{ .Values.services.objectStore.port }}'
|
||||
couchdb: 'http://{{ .Release.Name }}-svc-couchdb:{{ .Values.services.couchdb.port }}'
|
||||
resources: {}
|
||||
# annotations:
|
||||
# co.elastic.logs/module: nginx
|
||||
# co.elastic.logs/fileset.stdout: access
|
||||
# co.elastic.logs/fileset.stderr: error
|
||||
|
||||
apps:
|
||||
port: 4002
|
||||
|
@ -148,11 +135,20 @@ services:
|
|||
logLevel: info
|
||||
resources: {}
|
||||
# nodeDebug: "" # set the value of NODE_DEBUG
|
||||
|
||||
# annotations:
|
||||
# co.elastic.logs/multiline.type: pattern
|
||||
# co.elastic.logs/multiline.pattern: '^[[:space:]]'
|
||||
# co.elastic.logs/multiline.negate: false
|
||||
# co.elastic.logs/multiline.match: after
|
||||
worker:
|
||||
port: 4003
|
||||
replicaCount: 1
|
||||
resources: {}
|
||||
# annotations:
|
||||
# co.elastic.logs/multiline.type: pattern
|
||||
# co.elastic.logs/multiline.pattern: '^[[:space:]]'
|
||||
# co.elastic.logs/multiline.negate: false
|
||||
# co.elastic.logs/multiline.match: after
|
||||
|
||||
couchdb:
|
||||
enabled: true
|
||||
|
|
|
@ -6,7 +6,8 @@ services:
|
|||
minio-service:
|
||||
container_name: budi-minio-dev
|
||||
restart: on-failure
|
||||
image: minio/minio
|
||||
# Last version that supports the "fs" backend
|
||||
image: minio/minio:RELEASE.2022-10-24T18-35-07Z
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
ports:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.2.12-alpha.2",
|
||||
"version": "2.2.12-alpha.32",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -6,6 +6,9 @@ const config: Config.InitialOptions = {
|
|||
setupFiles: ["./tests/jestSetup.ts"],
|
||||
collectCoverageFrom: ["src/**/*.{js,ts}"],
|
||||
coverageReporters: ["lcov", "json", "clover"],
|
||||
transform: {
|
||||
"^.+\\.ts?$": "@swc/jest",
|
||||
},
|
||||
}
|
||||
|
||||
if (!process.env.CI) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "2.2.12-alpha.2",
|
||||
"version": "2.2.12-alpha.32",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@budibase/nano": "10.1.1",
|
||||
"@budibase/types": "2.2.12-alpha.2",
|
||||
"@budibase/types": "2.2.12-alpha.32",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-cloudfront-sign": "2.2.0",
|
||||
|
@ -31,6 +31,7 @@
|
|||
"bcrypt": "5.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bull": "4.10.1",
|
||||
"correlation-id": "4.0.0",
|
||||
"dotenv": "16.0.1",
|
||||
"emitter-listener": "1.1.2",
|
||||
"ioredis": "4.28.0",
|
||||
|
@ -56,19 +57,23 @@
|
|||
"zlib": "1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/core": "^1.3.25",
|
||||
"@swc/jest": "^0.2.24",
|
||||
"@types/chance": "1.1.3",
|
||||
"@types/ioredis": "4.28.0",
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/koa": "2.13.4",
|
||||
"@types/koa-pino-logger": "3.0.0",
|
||||
"@types/lodash": "4.14.180",
|
||||
"@types/node": "14.18.20",
|
||||
"@types/node-fetch": "2.6.1",
|
||||
"@types/pino-http": "5.8.1",
|
||||
"@types/pouchdb": "6.4.0",
|
||||
"@types/redlock": "4.0.3",
|
||||
"@types/semver": "7.3.7",
|
||||
"@types/tar-fs": "2.0.1",
|
||||
"@types/uuid": "8.3.4",
|
||||
"chance": "1.1.3",
|
||||
"chance": "1.1.8",
|
||||
"ioredis-mock": "5.8.0",
|
||||
"jest": "28.1.1",
|
||||
"koa": "2.13.4",
|
||||
|
|
|
@ -7,7 +7,7 @@ function generateTenantKey(key: string) {
|
|||
return `${key}:${tenantId}`
|
||||
}
|
||||
|
||||
export = class BaseCache {
|
||||
export default class BaseCache {
|
||||
client: Client | undefined
|
||||
|
||||
constructor(client: Client | undefined = undefined) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const BaseCache = require("./base")
|
||||
|
||||
const GENERIC = new BaseCache()
|
||||
const GENERIC = new BaseCache.default()
|
||||
|
||||
export enum CacheKey {
|
||||
CHECKLIST = "checklist",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import fetch from "node-fetch"
|
||||
import * as logging from "../logging"
|
||||
|
||||
export = class API {
|
||||
export default class API {
|
||||
host: string
|
||||
|
||||
constructor(host: string) {
|
||||
|
@ -22,6 +23,9 @@ export = class API {
|
|||
|
||||
let json = options.headers["Content-Type"] === "application/json"
|
||||
|
||||
// add x-budibase-correlation-id header
|
||||
logging.correlation.setHeader(options.headers)
|
||||
|
||||
const requestOptions = {
|
||||
method: method,
|
||||
body: json ? JSON.stringify(options.body) : options.body,
|
||||
|
|
|
@ -22,6 +22,7 @@ export enum Header {
|
|||
TENANT_ID = "x-budibase-tenant-id",
|
||||
TOKEN = "x-budibase-token",
|
||||
CSRF_TOKEN = "x-csrf-token",
|
||||
CORRELATION_ID = "x-budibase-correlation-id",
|
||||
}
|
||||
|
||||
export enum GlobalRole {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require("../../../tests")
|
||||
const context = require("../")
|
||||
const { DEFAULT_TENANT_ID } = require("../../constants")
|
||||
const env = require("../../environment")
|
||||
import env from "../../environment"
|
||||
|
||||
describe("context", () => {
|
||||
describe("doInTenant", () => {
|
||||
|
@ -26,7 +26,7 @@ describe("context", () => {
|
|||
|
||||
it("fails when no tenant id is set", () => {
|
||||
const test = () => {
|
||||
let error
|
||||
let error: any
|
||||
try {
|
||||
context.getTenantId()
|
||||
} catch (e) {
|
||||
|
@ -45,7 +45,7 @@ describe("context", () => {
|
|||
|
||||
it("fails when no tenant db is set", () => {
|
||||
const test = () => {
|
||||
let error
|
||||
let error: any
|
||||
try {
|
||||
context.getGlobalDB()
|
||||
} catch (e) {
|
|
@ -5,18 +5,13 @@ const {
|
|||
isDevAppID,
|
||||
isProdAppID,
|
||||
} = require("../conversions")
|
||||
const {
|
||||
generateAppID,
|
||||
getPlatformUrl,
|
||||
getScopedConfig
|
||||
} = require("../utils")
|
||||
const { generateAppID, getPlatformUrl, getScopedConfig } = require("../utils")
|
||||
const tenancy = require("../../tenancy")
|
||||
const { Config, DEFAULT_TENANT_ID } = require("../../constants")
|
||||
const env = require("../../environment")
|
||||
import env from "../../environment"
|
||||
|
||||
describe("utils", () => {
|
||||
describe("app ID manipulation", () => {
|
||||
|
||||
function getID() {
|
||||
const appId = generateAppID()
|
||||
const split = appId.split("_")
|
||||
|
@ -28,42 +23,42 @@ describe("utils", () => {
|
|||
it("should be able to generate a new app ID", () => {
|
||||
expect(generateAppID().startsWith("app_")).toEqual(true)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to convert a production app ID to development", () => {
|
||||
const { appId, uuid } = getID()
|
||||
expect(getDevelopmentAppID(appId)).toEqual(`app_dev_${uuid}`)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to convert a development app ID to development", () => {
|
||||
const { devAppId, uuid } = getID()
|
||||
expect(getDevelopmentAppID(devAppId)).toEqual(`app_dev_${uuid}`)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to convert a development ID to a production", () => {
|
||||
const { devAppId, uuid } = getID()
|
||||
expect(getProdAppID(devAppId)).toEqual(`app_${uuid}`)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to convert a production ID to production", () => {
|
||||
const { appId, uuid } = getID()
|
||||
expect(getProdAppID(appId)).toEqual(`app_${uuid}`)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to confirm dev app ID is development", () => {
|
||||
const { devAppId } = getID()
|
||||
expect(isDevAppID(devAppId)).toEqual(true)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to confirm prod app ID is not development", () => {
|
||||
const { appId } = getID()
|
||||
expect(isDevAppID(appId)).toEqual(false)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to confirm prod app ID is prod", () => {
|
||||
const { appId } = getID()
|
||||
expect(isProdAppID(appId)).toEqual(true)
|
||||
})
|
||||
|
||||
|
||||
it("should be able to confirm dev app ID is not prod", () => {
|
||||
const { devAppId } = getID()
|
||||
expect(isProdAppID(devAppId)).toEqual(false)
|
||||
|
@ -81,8 +76,8 @@ const setDbPlatformUrl = async () => {
|
|||
_id: "config_settings",
|
||||
type: Config.SETTINGS,
|
||||
config: {
|
||||
platformUrl: DB_URL
|
||||
}
|
||||
platformUrl: DB_URL,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,17 +87,16 @@ const clearSettingsConfig = async () => {
|
|||
try {
|
||||
const config = await db.get("config_settings")
|
||||
await db.remove("config_settings", config._rev)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e.status !== 404) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
describe("getPlatformUrl", () => {
|
||||
describe("self host", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
env._set("SELF_HOST", 1)
|
||||
await clearSettingsConfig()
|
||||
|
@ -129,10 +123,9 @@ describe("getPlatformUrl", () => {
|
|||
const url = await getPlatformUrl()
|
||||
expect(url).toBe(DB_URL)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe("cloud", () => {
|
||||
const TENANT_AWARE_URL = "http://default.env.com"
|
||||
|
||||
|
@ -163,13 +156,12 @@ describe("getPlatformUrl", () => {
|
|||
const url = await getPlatformUrl()
|
||||
expect(url).toBe(TENANT_AWARE_URL)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getScopedConfig", () => {
|
||||
describe("settings config", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
env._set("SELF_HOSTED", 1)
|
||||
env._set("PLATFORM_URL", "")
|
|
@ -102,4 +102,4 @@ for (let [key, value] of Object.entries(environment)) {
|
|||
}
|
||||
}
|
||||
|
||||
export = environment
|
||||
export default environment
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import * as licensing from "./licensing"
|
||||
|
||||
// combine all error codes into single object
|
||||
|
||||
export const codes = {
|
||||
...licensing.codes,
|
||||
}
|
||||
|
||||
// combine all error types
|
||||
export const types = [licensing.type]
|
||||
|
||||
// combine all error contexts
|
||||
const context = {
|
||||
...licensing.context,
|
||||
}
|
||||
|
||||
// derive a public error message using codes, types and any custom contexts
|
||||
export const getPublicError = (err: any) => {
|
||||
let error
|
||||
if (err.code || err.type) {
|
||||
// add generic error information
|
||||
error = {
|
||||
code: err.code,
|
||||
type: err.type,
|
||||
}
|
||||
|
||||
if (err.code && context[err.code]) {
|
||||
error = {
|
||||
...error,
|
||||
// get any additional context from this error
|
||||
...context[err.code](err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error
|
||||
}
|
|
@ -1,47 +1,3 @@
|
|||
import { HTTPError } from "./http"
|
||||
import { UsageLimitError, FeatureDisabledError } from "./licensing"
|
||||
import * as licensing from "./licensing"
|
||||
|
||||
const codes = {
|
||||
...licensing.codes,
|
||||
}
|
||||
|
||||
const types = [licensing.type]
|
||||
|
||||
const context = {
|
||||
...licensing.context,
|
||||
}
|
||||
|
||||
const getPublicError = (err: any) => {
|
||||
let error
|
||||
if (err.code || err.type) {
|
||||
// add generic error information
|
||||
error = {
|
||||
code: err.code,
|
||||
type: err.type,
|
||||
}
|
||||
|
||||
if (err.code && context[err.code]) {
|
||||
error = {
|
||||
...error,
|
||||
// get any additional context from this error
|
||||
...context[err.code](err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
const pkg = {
|
||||
codes,
|
||||
types,
|
||||
errors: {
|
||||
UsageLimitError,
|
||||
FeatureDisabledError,
|
||||
HTTPError,
|
||||
},
|
||||
getPublicError,
|
||||
}
|
||||
|
||||
export = pkg
|
||||
export * from "./errors"
|
||||
export { UsageLimitError, FeatureDisabledError } from "./licensing"
|
||||
export { HTTPError } from "./http"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Event } from "@budibase/types"
|
||||
import { processors } from "./processors"
|
||||
import * as identification from "./identification"
|
||||
import identification from "./identification"
|
||||
import * as backfill from "./backfill"
|
||||
|
||||
export const publishEvent = async (
|
||||
|
|
|
@ -33,7 +33,7 @@ const pkg = require("../../package.json")
|
|||
* - tenant
|
||||
* - installation
|
||||
*/
|
||||
export const getCurrentIdentity = async (): Promise<Identity> => {
|
||||
const getCurrentIdentity = async (): Promise<Identity> => {
|
||||
let identityContext = identityCtx.getIdentity()
|
||||
const environment = getDeploymentEnvironment()
|
||||
|
||||
|
@ -94,7 +94,7 @@ export const getCurrentIdentity = async (): Promise<Identity> => {
|
|||
}
|
||||
}
|
||||
|
||||
export const identifyInstallationGroup = async (
|
||||
const identifyInstallationGroup = async (
|
||||
installId: string,
|
||||
timestamp?: string | number
|
||||
): Promise<void> => {
|
||||
|
@ -118,7 +118,7 @@ export const identifyInstallationGroup = async (
|
|||
await identify({ ...group, id: `$${type}_${id}` }, timestamp)
|
||||
}
|
||||
|
||||
export const identifyTenantGroup = async (
|
||||
const identifyTenantGroup = async (
|
||||
tenantId: string,
|
||||
account: Account | undefined,
|
||||
timestamp?: string | number
|
||||
|
@ -156,7 +156,7 @@ export const identifyTenantGroup = async (
|
|||
await identify({ ...group, id: `$${type}_${id}` }, timestamp)
|
||||
}
|
||||
|
||||
export const identifyUser = async (
|
||||
const identifyUser = async (
|
||||
user: User,
|
||||
account: CloudAccount | undefined,
|
||||
timestamp?: string | number
|
||||
|
@ -191,7 +191,7 @@ export const identifyUser = async (
|
|||
await identify(identity, timestamp)
|
||||
}
|
||||
|
||||
export const identifyAccount = async (account: Account) => {
|
||||
const identifyAccount = async (account: Account) => {
|
||||
let id = account.accountId
|
||||
const tenantId = account.tenantId
|
||||
let type = IdentityType.USER
|
||||
|
@ -224,17 +224,11 @@ export const identifyAccount = async (account: Account) => {
|
|||
await identify(identity)
|
||||
}
|
||||
|
||||
export const identify = async (
|
||||
identity: Identity,
|
||||
timestamp?: string | number
|
||||
) => {
|
||||
const identify = async (identity: Identity, timestamp?: string | number) => {
|
||||
await processors.identify(identity, timestamp)
|
||||
}
|
||||
|
||||
export const identifyGroup = async (
|
||||
group: Group,
|
||||
timestamp?: string | number
|
||||
) => {
|
||||
const identifyGroup = async (group: Group, timestamp?: string | number) => {
|
||||
await processors.identifyGroup(group, timestamp)
|
||||
}
|
||||
|
||||
|
@ -250,7 +244,7 @@ const getHostingFromEnv = () => {
|
|||
return env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD
|
||||
}
|
||||
|
||||
export const getInstallationId = async () => {
|
||||
const getInstallationId = async () => {
|
||||
if (isAccountPortal()) {
|
||||
return "account-portal"
|
||||
}
|
||||
|
@ -300,3 +294,14 @@ const formatDistinctId = (id: string, type: IdentityType) => {
|
|||
return id
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getCurrentIdentity,
|
||||
identifyInstallationGroup,
|
||||
identifyTenantGroup,
|
||||
identifyUser,
|
||||
identifyAccount,
|
||||
identify,
|
||||
identifyGroup,
|
||||
getInstallationId,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export * from "./publishers"
|
||||
export * as processors from "./processors"
|
||||
export * as analytics from "./analytics"
|
||||
export * as identification from "./identification"
|
||||
export { default as identification } from "./identification"
|
||||
export * as backfillCache from "./backfill"
|
||||
|
||||
import { processors } from "./processors"
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class LoggingProcessor implements EventProcessor {
|
|||
return
|
||||
}
|
||||
let timestampString = getTimestampString(timestamp)
|
||||
let message = `[audit] [tenant=${identity.tenantId}] [identityType=${identity.type}] [identity=${identity.id}] ${timestampString} ${event} `
|
||||
let message = `[audit] [identityType=${identity.type}] ${timestampString} ${event} `
|
||||
if (env.isDev()) {
|
||||
message = message + `[debug: [properties=${JSON.stringify(properties)}] ]`
|
||||
}
|
||||
|
|
|
@ -7,23 +7,29 @@ import {
|
|||
AccountVerifiedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(account: Account) {
|
||||
async function created(account: Account) {
|
||||
const properties: AccountCreatedEvent = {
|
||||
tenantId: account.tenantId,
|
||||
}
|
||||
await publishEvent(Event.ACCOUNT_CREATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(account: Account) {
|
||||
async function deleted(account: Account) {
|
||||
const properties: AccountDeletedEvent = {
|
||||
tenantId: account.tenantId,
|
||||
}
|
||||
await publishEvent(Event.ACCOUNT_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function verified(account: Account) {
|
||||
async function verified(account: Account) {
|
||||
const properties: AccountVerifiedEvent = {
|
||||
tenantId: account.tenantId,
|
||||
}
|
||||
await publishEvent(Event.ACCOUNT_VERIFIED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
deleted,
|
||||
verified,
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
AppExportedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export const created = async (app: App, timestamp?: string | number) => {
|
||||
const created = async (app: App, timestamp?: string | number) => {
|
||||
const properties: AppCreatedEvent = {
|
||||
appId: app.appId,
|
||||
version: app.version,
|
||||
|
@ -23,7 +23,7 @@ export const created = async (app: App, timestamp?: string | number) => {
|
|||
await publishEvent(Event.APP_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(app: App) {
|
||||
async function updated(app: App) {
|
||||
const properties: AppUpdatedEvent = {
|
||||
appId: app.appId,
|
||||
version: app.version,
|
||||
|
@ -31,35 +31,35 @@ export async function updated(app: App) {
|
|||
await publishEvent(Event.APP_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(app: App) {
|
||||
async function deleted(app: App) {
|
||||
const properties: AppDeletedEvent = {
|
||||
appId: app.appId,
|
||||
}
|
||||
await publishEvent(Event.APP_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function published(app: App, timestamp?: string | number) {
|
||||
async function published(app: App, timestamp?: string | number) {
|
||||
const properties: AppPublishedEvent = {
|
||||
appId: app.appId,
|
||||
}
|
||||
await publishEvent(Event.APP_PUBLISHED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function unpublished(app: App) {
|
||||
async function unpublished(app: App) {
|
||||
const properties: AppUnpublishedEvent = {
|
||||
appId: app.appId,
|
||||
}
|
||||
await publishEvent(Event.APP_UNPUBLISHED, properties)
|
||||
}
|
||||
|
||||
export async function fileImported(app: App) {
|
||||
async function fileImported(app: App) {
|
||||
const properties: AppFileImportedEvent = {
|
||||
appId: app.appId,
|
||||
}
|
||||
await publishEvent(Event.APP_FILE_IMPORTED, properties)
|
||||
}
|
||||
|
||||
export async function templateImported(app: App, templateKey: string) {
|
||||
async function templateImported(app: App, templateKey: string) {
|
||||
const properties: AppTemplateImportedEvent = {
|
||||
appId: app.appId,
|
||||
templateKey,
|
||||
|
@ -67,7 +67,7 @@ export async function templateImported(app: App, templateKey: string) {
|
|||
await publishEvent(Event.APP_TEMPLATE_IMPORTED, properties)
|
||||
}
|
||||
|
||||
export async function versionUpdated(
|
||||
async function versionUpdated(
|
||||
app: App,
|
||||
currentVersion: string,
|
||||
updatedToVersion: string
|
||||
|
@ -80,7 +80,7 @@ export async function versionUpdated(
|
|||
await publishEvent(Event.APP_VERSION_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function versionReverted(
|
||||
async function versionReverted(
|
||||
app: App,
|
||||
currentVersion: string,
|
||||
revertedToVersion: string
|
||||
|
@ -93,16 +93,30 @@ export async function versionReverted(
|
|||
await publishEvent(Event.APP_VERSION_REVERTED, properties)
|
||||
}
|
||||
|
||||
export async function reverted(app: App) {
|
||||
async function reverted(app: App) {
|
||||
const properties: AppRevertedEvent = {
|
||||
appId: app.appId,
|
||||
}
|
||||
await publishEvent(Event.APP_REVERTED, properties)
|
||||
}
|
||||
|
||||
export async function exported(app: App) {
|
||||
async function exported(app: App) {
|
||||
const properties: AppExportedEvent = {
|
||||
appId: app.appId,
|
||||
}
|
||||
await publishEvent(Event.APP_EXPORTED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
published,
|
||||
unpublished,
|
||||
fileImported,
|
||||
templateImported,
|
||||
versionUpdated,
|
||||
versionReverted,
|
||||
reverted,
|
||||
exported,
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from "@budibase/types"
|
||||
import { identification } from ".."
|
||||
|
||||
export async function login(source: LoginSource) {
|
||||
async function login(source: LoginSource) {
|
||||
const identity = await identification.getCurrentIdentity()
|
||||
const properties: LoginEvent = {
|
||||
userId: identity.id,
|
||||
|
@ -21,7 +21,7 @@ export async function login(source: LoginSource) {
|
|||
await publishEvent(Event.AUTH_LOGIN, properties)
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
async function logout() {
|
||||
const identity = await identification.getCurrentIdentity()
|
||||
const properties: LogoutEvent = {
|
||||
userId: identity.id,
|
||||
|
@ -29,30 +29,39 @@ export async function logout() {
|
|||
await publishEvent(Event.AUTH_LOGOUT, properties)
|
||||
}
|
||||
|
||||
export async function SSOCreated(type: SSOType, timestamp?: string | number) {
|
||||
async function SSOCreated(type: SSOType, timestamp?: string | number) {
|
||||
const properties: SSOCreatedEvent = {
|
||||
type,
|
||||
}
|
||||
await publishEvent(Event.AUTH_SSO_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function SSOUpdated(type: SSOType) {
|
||||
async function SSOUpdated(type: SSOType) {
|
||||
const properties: SSOUpdatedEvent = {
|
||||
type,
|
||||
}
|
||||
await publishEvent(Event.AUTH_SSO_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function SSOActivated(type: SSOType, timestamp?: string | number) {
|
||||
async function SSOActivated(type: SSOType, timestamp?: string | number) {
|
||||
const properties: SSOActivatedEvent = {
|
||||
type,
|
||||
}
|
||||
await publishEvent(Event.AUTH_SSO_ACTIVATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function SSODeactivated(type: SSOType) {
|
||||
async function SSODeactivated(type: SSOType) {
|
||||
const properties: SSODeactivatedEvent = {
|
||||
type,
|
||||
}
|
||||
await publishEvent(Event.AUTH_SSO_DEACTIVATED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
login,
|
||||
logout,
|
||||
SSOCreated,
|
||||
SSOUpdated,
|
||||
SSOActivated,
|
||||
SSODeactivated,
|
||||
}
|
||||
|
|
|
@ -12,10 +12,7 @@ import {
|
|||
AutomationsRunEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(
|
||||
automation: Automation,
|
||||
timestamp?: string | number
|
||||
) {
|
||||
async function created(automation: Automation, timestamp?: string | number) {
|
||||
const properties: AutomationCreatedEvent = {
|
||||
appId: automation.appId,
|
||||
automationId: automation._id as string,
|
||||
|
@ -25,7 +22,7 @@ export async function created(
|
|||
await publishEvent(Event.AUTOMATION_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function triggerUpdated(automation: Automation) {
|
||||
async function triggerUpdated(automation: Automation) {
|
||||
const properties: AutomationTriggerUpdatedEvent = {
|
||||
appId: automation.appId,
|
||||
automationId: automation._id as string,
|
||||
|
@ -35,7 +32,7 @@ export async function triggerUpdated(automation: Automation) {
|
|||
await publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(automation: Automation) {
|
||||
async function deleted(automation: Automation) {
|
||||
const properties: AutomationDeletedEvent = {
|
||||
appId: automation.appId,
|
||||
automationId: automation._id as string,
|
||||
|
@ -45,7 +42,7 @@ export async function deleted(automation: Automation) {
|
|||
await publishEvent(Event.AUTOMATION_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function tested(automation: Automation) {
|
||||
async function tested(automation: Automation) {
|
||||
const properties: AutomationTestedEvent = {
|
||||
appId: automation.appId,
|
||||
automationId: automation._id as string,
|
||||
|
@ -55,14 +52,14 @@ export async function tested(automation: Automation) {
|
|||
await publishEvent(Event.AUTOMATION_TESTED, properties)
|
||||
}
|
||||
|
||||
export const run = async (count: number, timestamp?: string | number) => {
|
||||
const run = async (count: number, timestamp?: string | number) => {
|
||||
const properties: AutomationsRunEvent = {
|
||||
count,
|
||||
}
|
||||
await publishEvent(Event.AUTOMATIONS_RUN, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function stepCreated(
|
||||
async function stepCreated(
|
||||
automation: Automation,
|
||||
step: AutomationStep,
|
||||
timestamp?: string | number
|
||||
|
@ -78,10 +75,7 @@ export async function stepCreated(
|
|||
await publishEvent(Event.AUTOMATION_STEP_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function stepDeleted(
|
||||
automation: Automation,
|
||||
step: AutomationStep
|
||||
) {
|
||||
async function stepDeleted(automation: Automation, step: AutomationStep) {
|
||||
const properties: AutomationStepDeletedEvent = {
|
||||
appId: automation.appId,
|
||||
automationId: automation._id as string,
|
||||
|
@ -92,3 +86,13 @@ export async function stepDeleted(
|
|||
}
|
||||
await publishEvent(Event.AUTOMATION_STEP_DELETED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
triggerUpdated,
|
||||
deleted,
|
||||
tested,
|
||||
run,
|
||||
stepCreated,
|
||||
stepDeleted,
|
||||
}
|
||||
|
|
|
@ -8,18 +8,18 @@ import {
|
|||
InstallationBackfillSucceededEvent,
|
||||
InstallationBackfillFailedEvent,
|
||||
} from "@budibase/types"
|
||||
const env = require("../../environment")
|
||||
import env from "../../environment"
|
||||
|
||||
const shouldSkip = !env.SELF_HOSTED && !env.isDev()
|
||||
|
||||
export async function appSucceeded(properties: AppBackfillSucceededEvent) {
|
||||
async function appSucceeded(properties: AppBackfillSucceededEvent) {
|
||||
if (shouldSkip) {
|
||||
return
|
||||
}
|
||||
await publishEvent(Event.APP_BACKFILL_SUCCEEDED, properties)
|
||||
}
|
||||
|
||||
export async function appFailed(error: any) {
|
||||
async function appFailed(error: any) {
|
||||
if (shouldSkip) {
|
||||
return
|
||||
}
|
||||
|
@ -29,16 +29,14 @@ export async function appFailed(error: any) {
|
|||
await publishEvent(Event.APP_BACKFILL_FAILED, properties)
|
||||
}
|
||||
|
||||
export async function tenantSucceeded(
|
||||
properties: TenantBackfillSucceededEvent
|
||||
) {
|
||||
async function tenantSucceeded(properties: TenantBackfillSucceededEvent) {
|
||||
if (shouldSkip) {
|
||||
return
|
||||
}
|
||||
await publishEvent(Event.TENANT_BACKFILL_SUCCEEDED, properties)
|
||||
}
|
||||
|
||||
export async function tenantFailed(error: any) {
|
||||
async function tenantFailed(error: any) {
|
||||
if (shouldSkip) {
|
||||
return
|
||||
}
|
||||
|
@ -48,7 +46,7 @@ export async function tenantFailed(error: any) {
|
|||
await publishEvent(Event.TENANT_BACKFILL_FAILED, properties)
|
||||
}
|
||||
|
||||
export async function installationSucceeded() {
|
||||
async function installationSucceeded() {
|
||||
if (shouldSkip) {
|
||||
return
|
||||
}
|
||||
|
@ -56,7 +54,7 @@ export async function installationSucceeded() {
|
|||
await publishEvent(Event.INSTALLATION_BACKFILL_SUCCEEDED, properties)
|
||||
}
|
||||
|
||||
export async function installationFailed(error: any) {
|
||||
async function installationFailed(error: any) {
|
||||
if (shouldSkip) {
|
||||
return
|
||||
}
|
||||
|
@ -65,3 +63,12 @@ export async function installationFailed(error: any) {
|
|||
}
|
||||
await publishEvent(Event.INSTALLATION_BACKFILL_FAILED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
appSucceeded,
|
||||
appFailed,
|
||||
tenantSucceeded,
|
||||
tenantFailed,
|
||||
installationSucceeded,
|
||||
installationFailed,
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from "@budibase/types"
|
||||
import { publishEvent } from "../events"
|
||||
|
||||
export async function appBackupRestored(backup: AppBackup) {
|
||||
async function appBackupRestored(backup: AppBackup) {
|
||||
const properties: AppBackupRestoreEvent = {
|
||||
appId: backup.appId,
|
||||
restoreId: backup._id!,
|
||||
|
@ -18,7 +18,7 @@ export async function appBackupRestored(backup: AppBackup) {
|
|||
await publishEvent(Event.APP_BACKUP_RESTORED, properties)
|
||||
}
|
||||
|
||||
export async function appBackupTriggered(
|
||||
async function appBackupTriggered(
|
||||
appId: string,
|
||||
backupId: string,
|
||||
type: AppBackupType,
|
||||
|
@ -32,3 +32,8 @@ export async function appBackupTriggered(
|
|||
}
|
||||
await publishEvent(Event.APP_BACKUP_TRIGGERED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
appBackupRestored,
|
||||
appBackupTriggered,
|
||||
}
|
||||
|
|
|
@ -14,10 +14,7 @@ function isCustom(datasource: Datasource) {
|
|||
return !sources.includes(datasource.source)
|
||||
}
|
||||
|
||||
export async function created(
|
||||
datasource: Datasource,
|
||||
timestamp?: string | number
|
||||
) {
|
||||
async function created(datasource: Datasource, timestamp?: string | number) {
|
||||
const properties: DatasourceCreatedEvent = {
|
||||
datasourceId: datasource._id as string,
|
||||
source: datasource.source,
|
||||
|
@ -26,7 +23,7 @@ export async function created(
|
|||
await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(datasource: Datasource) {
|
||||
async function updated(datasource: Datasource) {
|
||||
const properties: DatasourceUpdatedEvent = {
|
||||
datasourceId: datasource._id as string,
|
||||
source: datasource.source,
|
||||
|
@ -35,7 +32,7 @@ export async function updated(datasource: Datasource) {
|
|||
await publishEvent(Event.DATASOURCE_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(datasource: Datasource) {
|
||||
async function deleted(datasource: Datasource) {
|
||||
const properties: DatasourceDeletedEvent = {
|
||||
datasourceId: datasource._id as string,
|
||||
source: datasource.source,
|
||||
|
@ -43,3 +40,9 @@ export async function deleted(datasource: Datasource) {
|
|||
}
|
||||
await publishEvent(Event.DATASOURCE_DELETED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import { publishEvent } from "../events"
|
||||
import { Event, SMTPCreatedEvent, SMTPUpdatedEvent } from "@budibase/types"
|
||||
|
||||
export async function SMTPCreated(timestamp?: string | number) {
|
||||
async function SMTPCreated(timestamp?: string | number) {
|
||||
const properties: SMTPCreatedEvent = {}
|
||||
await publishEvent(Event.EMAIL_SMTP_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function SMTPUpdated() {
|
||||
async function SMTPUpdated() {
|
||||
const properties: SMTPUpdatedEvent = {}
|
||||
await publishEvent(Event.EMAIL_SMTP_UPDATED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
SMTPCreated,
|
||||
SMTPUpdated,
|
||||
}
|
||||
|
|
|
@ -11,28 +11,28 @@ import {
|
|||
UserGroupRoles,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(group: UserGroup, timestamp?: number) {
|
||||
async function created(group: UserGroup, timestamp?: number) {
|
||||
const properties: GroupCreatedEvent = {
|
||||
groupId: group._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_GROUP_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(group: UserGroup) {
|
||||
async function updated(group: UserGroup) {
|
||||
const properties: GroupUpdatedEvent = {
|
||||
groupId: group._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_GROUP_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(group: UserGroup) {
|
||||
async function deleted(group: UserGroup) {
|
||||
const properties: GroupDeletedEvent = {
|
||||
groupId: group._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_GROUP_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function usersAdded(count: number, group: UserGroup) {
|
||||
async function usersAdded(count: number, group: UserGroup) {
|
||||
const properties: GroupUsersAddedEvent = {
|
||||
count,
|
||||
groupId: group._id as string,
|
||||
|
@ -40,7 +40,7 @@ export async function usersAdded(count: number, group: UserGroup) {
|
|||
await publishEvent(Event.USER_GROUP_USERS_ADDED, properties)
|
||||
}
|
||||
|
||||
export async function usersDeleted(count: number, group: UserGroup) {
|
||||
async function usersDeleted(count: number, group: UserGroup) {
|
||||
const properties: GroupUsersDeletedEvent = {
|
||||
count,
|
||||
groupId: group._id as string,
|
||||
|
@ -48,7 +48,7 @@ export async function usersDeleted(count: number, group: UserGroup) {
|
|||
await publishEvent(Event.USER_GROUP_USERS_REMOVED, properties)
|
||||
}
|
||||
|
||||
export async function createdOnboarding(groupId: string) {
|
||||
async function createdOnboarding(groupId: string) {
|
||||
const properties: GroupAddedOnboardingEvent = {
|
||||
groupId: groupId,
|
||||
onboarding: true,
|
||||
|
@ -56,9 +56,19 @@ export async function createdOnboarding(groupId: string) {
|
|||
await publishEvent(Event.USER_GROUP_ONBOARDING, properties)
|
||||
}
|
||||
|
||||
export async function permissionsEdited(roles: UserGroupRoles) {
|
||||
async function permissionsEdited(roles: UserGroupRoles) {
|
||||
const properties: UserGroupRoles = {
|
||||
...roles,
|
||||
}
|
||||
await publishEvent(Event.USER_GROUP_PERMISSIONS_EDITED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
usersAdded,
|
||||
usersDeleted,
|
||||
createdOnboarding,
|
||||
permissionsEdited,
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
export * as account from "./account"
|
||||
export * as app from "./app"
|
||||
export * as auth from "./auth"
|
||||
export * as automation from "./automation"
|
||||
export * as datasource from "./datasource"
|
||||
export * as email from "./email"
|
||||
export * as license from "./license"
|
||||
export * as layout from "./layout"
|
||||
export * as org from "./org"
|
||||
export * as query from "./query"
|
||||
export * as role from "./role"
|
||||
export * as screen from "./screen"
|
||||
export * as rows from "./rows"
|
||||
export * as table from "./table"
|
||||
export * as serve from "./serve"
|
||||
export * as user from "./user"
|
||||
export * as view from "./view"
|
||||
export * as installation from "./installation"
|
||||
export * as backfill from "./backfill"
|
||||
export * as group from "./group"
|
||||
export * as plugin from "./plugin"
|
||||
export * as backup from "./backup"
|
||||
export { default as account } from "./account"
|
||||
export { default as app } from "./app"
|
||||
export { default as auth } from "./auth"
|
||||
export { default as automation } from "./automation"
|
||||
export { default as datasource } from "./datasource"
|
||||
export { default as email } from "./email"
|
||||
export { default as license } from "./license"
|
||||
export { default as layout } from "./layout"
|
||||
export { default as org } from "./org"
|
||||
export { default as query } from "./query"
|
||||
export { default as role } from "./role"
|
||||
export { default as screen } from "./screen"
|
||||
export { default as rows } from "./rows"
|
||||
export { default as table } from "./table"
|
||||
export { default as serve } from "./serve"
|
||||
export { default as user } from "./user"
|
||||
export { default as view } from "./view"
|
||||
export { default as installation } from "./installation"
|
||||
export { default as backfill } from "./backfill"
|
||||
export { default as group } from "./group"
|
||||
export { default as plugin } from "./plugin"
|
||||
export { default as backup } from "./backup"
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { publishEvent } from "../events"
|
||||
import { Event, VersionCheckedEvent, VersionChangeEvent } from "@budibase/types"
|
||||
|
||||
export async function versionChecked(version: string) {
|
||||
async function versionChecked(version: string) {
|
||||
const properties: VersionCheckedEvent = {
|
||||
currentVersion: version,
|
||||
}
|
||||
await publishEvent(Event.INSTALLATION_VERSION_CHECKED, properties)
|
||||
}
|
||||
|
||||
export async function upgraded(from: string, to: string) {
|
||||
async function upgraded(from: string, to: string) {
|
||||
const properties: VersionChangeEvent = {
|
||||
from,
|
||||
to,
|
||||
|
@ -17,7 +17,7 @@ export async function upgraded(from: string, to: string) {
|
|||
await publishEvent(Event.INSTALLATION_VERSION_UPGRADED, properties)
|
||||
}
|
||||
|
||||
export async function downgraded(from: string, to: string) {
|
||||
async function downgraded(from: string, to: string) {
|
||||
const properties: VersionChangeEvent = {
|
||||
from,
|
||||
to,
|
||||
|
@ -25,7 +25,14 @@ export async function downgraded(from: string, to: string) {
|
|||
await publishEvent(Event.INSTALLATION_VERSION_DOWNGRADED, properties)
|
||||
}
|
||||
|
||||
export async function firstStartup() {
|
||||
async function firstStartup() {
|
||||
const properties = {}
|
||||
await publishEvent(Event.INSTALLATION_FIRST_STARTUP, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
versionChecked,
|
||||
upgraded,
|
||||
downgraded,
|
||||
firstStartup,
|
||||
}
|
||||
|
|
|
@ -6,16 +6,21 @@ import {
|
|||
LayoutDeletedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(layout: Layout, timestamp?: string | number) {
|
||||
async function created(layout: Layout, timestamp?: string | number) {
|
||||
const properties: LayoutCreatedEvent = {
|
||||
layoutId: layout._id as string,
|
||||
}
|
||||
await publishEvent(Event.LAYOUT_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function deleted(layoutId: string) {
|
||||
async function deleted(layoutId: string) {
|
||||
const properties: LayoutDeletedEvent = {
|
||||
layoutId,
|
||||
}
|
||||
await publishEvent(Event.LAYOUT_DELETED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
deleted,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
LicensePaymentRecoveredEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function tierChanged(account: Account, from: number, to: number) {
|
||||
async function tierChanged(account: Account, from: number, to: number) {
|
||||
const properties: LicenseTierChangedEvent = {
|
||||
accountId: account.accountId,
|
||||
to,
|
||||
|
@ -22,11 +22,7 @@ export async function tierChanged(account: Account, from: number, to: number) {
|
|||
await publishEvent(Event.LICENSE_TIER_CHANGED, properties)
|
||||
}
|
||||
|
||||
export async function planChanged(
|
||||
account: Account,
|
||||
from: PlanType,
|
||||
to: PlanType
|
||||
) {
|
||||
async function planChanged(account: Account, from: PlanType, to: PlanType) {
|
||||
const properties: LicensePlanChangedEvent = {
|
||||
accountId: account.accountId,
|
||||
to,
|
||||
|
@ -35,44 +31,55 @@ export async function planChanged(
|
|||
await publishEvent(Event.LICENSE_PLAN_CHANGED, properties)
|
||||
}
|
||||
|
||||
export async function activated(account: Account) {
|
||||
async function activated(account: Account) {
|
||||
const properties: LicenseActivatedEvent = {
|
||||
accountId: account.accountId,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_ACTIVATED, properties)
|
||||
}
|
||||
|
||||
export async function checkoutOpened(account: Account) {
|
||||
async function checkoutOpened(account: Account) {
|
||||
const properties: LicenseCheckoutOpenedEvent = {
|
||||
accountId: account.accountId,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_CHECKOUT_OPENED, properties)
|
||||
}
|
||||
|
||||
export async function checkoutSuccess(account: Account) {
|
||||
async function checkoutSuccess(account: Account) {
|
||||
const properties: LicenseCheckoutSuccessEvent = {
|
||||
accountId: account.accountId,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_CHECKOUT_SUCCESS, properties)
|
||||
}
|
||||
|
||||
export async function portalOpened(account: Account) {
|
||||
async function portalOpened(account: Account) {
|
||||
const properties: LicensePortalOpenedEvent = {
|
||||
accountId: account.accountId,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_PORTAL_OPENED, properties)
|
||||
}
|
||||
|
||||
export async function paymentFailed(account: Account) {
|
||||
async function paymentFailed(account: Account) {
|
||||
const properties: LicensePaymentFailedEvent = {
|
||||
accountId: account.accountId,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_PAYMENT_FAILED, properties)
|
||||
}
|
||||
|
||||
export async function paymentRecovered(account: Account) {
|
||||
async function paymentRecovered(account: Account) {
|
||||
const properties: LicensePaymentRecoveredEvent = {
|
||||
accountId: account.accountId,
|
||||
}
|
||||
await publishEvent(Event.LICENSE_PAYMENT_RECOVERED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
tierChanged,
|
||||
planChanged,
|
||||
activated,
|
||||
checkoutOpened,
|
||||
checkoutSuccess,
|
||||
portalOpened,
|
||||
paymentFailed,
|
||||
paymentRecovered,
|
||||
}
|
||||
|
|
|
@ -1,29 +1,37 @@
|
|||
import { publishEvent } from "../events"
|
||||
import { Event } from "@budibase/types"
|
||||
|
||||
export async function nameUpdated(timestamp?: string | number) {
|
||||
async function nameUpdated(timestamp?: string | number) {
|
||||
const properties = {}
|
||||
await publishEvent(Event.ORG_NAME_UPDATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function logoUpdated(timestamp?: string | number) {
|
||||
async function logoUpdated(timestamp?: string | number) {
|
||||
const properties = {}
|
||||
await publishEvent(Event.ORG_LOGO_UPDATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function platformURLUpdated(timestamp?: string | number) {
|
||||
async function platformURLUpdated(timestamp?: string | number) {
|
||||
const properties = {}
|
||||
await publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties, timestamp)
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
export async function analyticsOptOut() {
|
||||
async function analyticsOptOut() {
|
||||
const properties = {}
|
||||
await publishEvent(Event.ANALYTICS_OPT_OUT, properties)
|
||||
}
|
||||
|
||||
export async function analyticsOptIn() {
|
||||
async function analyticsOptIn() {
|
||||
const properties = {}
|
||||
await publishEvent(Event.ANALYTICS_OPT_OUT, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
nameUpdated,
|
||||
logoUpdated,
|
||||
platformURLUpdated,
|
||||
analyticsOptOut,
|
||||
analyticsOptIn,
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
PluginInitEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function init(plugin: Plugin) {
|
||||
async function init(plugin: Plugin) {
|
||||
const properties: PluginInitEvent = {
|
||||
type: plugin.schema.type,
|
||||
name: plugin.name,
|
||||
|
@ -17,7 +17,7 @@ export async function init(plugin: Plugin) {
|
|||
await publishEvent(Event.PLUGIN_INIT, properties)
|
||||
}
|
||||
|
||||
export async function imported(plugin: Plugin) {
|
||||
async function imported(plugin: Plugin) {
|
||||
const properties: PluginImportedEvent = {
|
||||
pluginId: plugin._id as string,
|
||||
type: plugin.schema.type,
|
||||
|
@ -29,7 +29,7 @@ export async function imported(plugin: Plugin) {
|
|||
await publishEvent(Event.PLUGIN_IMPORTED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(plugin: Plugin) {
|
||||
async function deleted(plugin: Plugin) {
|
||||
const properties: PluginDeletedEvent = {
|
||||
pluginId: plugin._id as string,
|
||||
type: plugin.schema.type,
|
||||
|
@ -39,3 +39,9 @@ export async function deleted(plugin: Plugin) {
|
|||
}
|
||||
await publishEvent(Event.PLUGIN_DELETED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
init,
|
||||
imported,
|
||||
deleted,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
|
||||
/* eslint-disable */
|
||||
|
||||
export const created = async (
|
||||
const created = async (
|
||||
datasource: Datasource,
|
||||
query: Query,
|
||||
timestamp?: string | number
|
||||
|
@ -27,7 +27,7 @@ export const created = async (
|
|||
await publishEvent(Event.QUERY_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export const updated = async (datasource: Datasource, query: Query) => {
|
||||
const updated = async (datasource: Datasource, query: Query) => {
|
||||
const properties: QueryUpdatedEvent = {
|
||||
queryId: query._id as string,
|
||||
datasourceId: datasource._id as string,
|
||||
|
@ -37,7 +37,7 @@ export const updated = async (datasource: Datasource, query: Query) => {
|
|||
await publishEvent(Event.QUERY_UPDATED, properties)
|
||||
}
|
||||
|
||||
export const deleted = async (datasource: Datasource, query: Query) => {
|
||||
const deleted = async (datasource: Datasource, query: Query) => {
|
||||
const properties: QueryDeletedEvent = {
|
||||
queryId: query._id as string,
|
||||
datasourceId: datasource._id as string,
|
||||
|
@ -47,7 +47,7 @@ export const deleted = async (datasource: Datasource, query: Query) => {
|
|||
await publishEvent(Event.QUERY_DELETED, properties)
|
||||
}
|
||||
|
||||
export const imported = async (
|
||||
const imported = async (
|
||||
datasource: Datasource,
|
||||
importSource: any,
|
||||
count: any
|
||||
|
@ -61,14 +61,14 @@ export const imported = async (
|
|||
await publishEvent(Event.QUERY_IMPORT, properties)
|
||||
}
|
||||
|
||||
export const run = async (count: number, timestamp?: string | number) => {
|
||||
const run = async (count: number, timestamp?: string | number) => {
|
||||
const properties: QueriesRunEvent = {
|
||||
count,
|
||||
}
|
||||
await publishEvent(Event.QUERIES_RUN, properties, timestamp)
|
||||
}
|
||||
|
||||
export const previewed = async (datasource: Datasource, query: Query) => {
|
||||
const previewed = async (datasource: Datasource, query: Query) => {
|
||||
const properties: QueryPreviewedEvent = {
|
||||
queryId: query._id,
|
||||
datasourceId: datasource._id as string,
|
||||
|
@ -77,3 +77,12 @@ export const previewed = async (datasource: Datasource, query: Query) => {
|
|||
}
|
||||
await publishEvent(Event.QUERY_PREVIEWED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
imported,
|
||||
run,
|
||||
previewed,
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
User,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(role: Role, timestamp?: string | number) {
|
||||
async function created(role: Role, timestamp?: string | number) {
|
||||
const properties: RoleCreatedEvent = {
|
||||
roleId: role._id as string,
|
||||
permissionId: role.permissionId,
|
||||
|
@ -19,7 +19,7 @@ export async function created(role: Role, timestamp?: string | number) {
|
|||
await publishEvent(Event.ROLE_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(role: Role) {
|
||||
async function updated(role: Role) {
|
||||
const properties: RoleUpdatedEvent = {
|
||||
roleId: role._id as string,
|
||||
permissionId: role.permissionId,
|
||||
|
@ -28,7 +28,7 @@ export async function updated(role: Role) {
|
|||
await publishEvent(Event.ROLE_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(role: Role) {
|
||||
async function deleted(role: Role) {
|
||||
const properties: RoleDeletedEvent = {
|
||||
roleId: role._id as string,
|
||||
permissionId: role.permissionId,
|
||||
|
@ -37,7 +37,7 @@ export async function deleted(role: Role) {
|
|||
await publishEvent(Event.ROLE_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function assigned(user: User, roleId: string, timestamp?: number) {
|
||||
async function assigned(user: User, roleId: string, timestamp?: number) {
|
||||
const properties: RoleAssignedEvent = {
|
||||
userId: user._id as string,
|
||||
roleId,
|
||||
|
@ -45,10 +45,18 @@ export async function assigned(user: User, roleId: string, timestamp?: number) {
|
|||
await publishEvent(Event.ROLE_ASSIGNED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function unassigned(user: User, roleId: string) {
|
||||
async function unassigned(user: User, roleId: string) {
|
||||
const properties: RoleUnassignedEvent = {
|
||||
userId: user._id as string,
|
||||
roleId,
|
||||
}
|
||||
await publishEvent(Event.ROLE_UNASSIGNED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
assigned,
|
||||
unassigned,
|
||||
}
|
||||
|
|
|
@ -3,28 +3,27 @@ import {
|
|||
Event,
|
||||
RowsImportedEvent,
|
||||
RowsCreatedEvent,
|
||||
RowImportFormat,
|
||||
Table,
|
||||
} from "@budibase/types"
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
export const created = async (count: number, timestamp?: string | number) => {
|
||||
const created = async (count: number, timestamp?: string | number) => {
|
||||
const properties: RowsCreatedEvent = {
|
||||
count,
|
||||
}
|
||||
await publishEvent(Event.ROWS_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export const imported = async (
|
||||
table: Table,
|
||||
format: RowImportFormat,
|
||||
count: number
|
||||
) => {
|
||||
const imported = async (table: Table, count: number) => {
|
||||
const properties: RowsImportedEvent = {
|
||||
tableId: table._id as string,
|
||||
format,
|
||||
count,
|
||||
}
|
||||
await publishEvent(Event.ROWS_IMPORTED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
imported,
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
ScreenDeletedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(screen: Screen, timestamp?: string | number) {
|
||||
async function created(screen: Screen, timestamp?: string | number) {
|
||||
const properties: ScreenCreatedEvent = {
|
||||
layoutId: screen.layoutId,
|
||||
screenId: screen._id as string,
|
||||
|
@ -15,7 +15,7 @@ export async function created(screen: Screen, timestamp?: string | number) {
|
|||
await publishEvent(Event.SCREEN_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function deleted(screen: Screen) {
|
||||
async function deleted(screen: Screen) {
|
||||
const properties: ScreenDeletedEvent = {
|
||||
layoutId: screen.layoutId,
|
||||
screenId: screen._id as string,
|
||||
|
@ -23,3 +23,8 @@ export async function deleted(screen: Screen) {
|
|||
}
|
||||
await publishEvent(Event.SCREEN_DELETED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
deleted,
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@ import {
|
|||
AppServedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function servedBuilder(timezone: string) {
|
||||
async function servedBuilder(timezone: string) {
|
||||
const properties: BuilderServedEvent = {
|
||||
timezone,
|
||||
}
|
||||
await publishEvent(Event.SERVED_BUILDER, properties)
|
||||
}
|
||||
|
||||
export async function servedApp(app: App, timezone: string) {
|
||||
async function servedApp(app: App, timezone: string) {
|
||||
const properties: AppServedEvent = {
|
||||
appVersion: app.version,
|
||||
timezone,
|
||||
|
@ -22,7 +22,7 @@ export async function servedApp(app: App, timezone: string) {
|
|||
await publishEvent(Event.SERVED_APP, properties)
|
||||
}
|
||||
|
||||
export async function servedAppPreview(app: App, timezone: string) {
|
||||
async function servedAppPreview(app: App, timezone: string) {
|
||||
const properties: AppPreviewServedEvent = {
|
||||
appId: app.appId,
|
||||
appVersion: app.version,
|
||||
|
@ -30,3 +30,9 @@ export async function servedAppPreview(app: App, timezone: string) {
|
|||
}
|
||||
await publishEvent(Event.SERVED_APP_PREVIEW, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
servedBuilder,
|
||||
servedApp,
|
||||
servedAppPreview,
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import { publishEvent } from "../events"
|
|||
import {
|
||||
Event,
|
||||
TableExportFormat,
|
||||
TableImportFormat,
|
||||
Table,
|
||||
TableCreatedEvent,
|
||||
TableUpdatedEvent,
|
||||
|
@ -11,28 +10,28 @@ import {
|
|||
TableImportedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(table: Table, timestamp?: string | number) {
|
||||
async function created(table: Table, timestamp?: string | number) {
|
||||
const properties: TableCreatedEvent = {
|
||||
tableId: table._id as string,
|
||||
}
|
||||
await publishEvent(Event.TABLE_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(table: Table) {
|
||||
async function updated(table: Table) {
|
||||
const properties: TableUpdatedEvent = {
|
||||
tableId: table._id as string,
|
||||
}
|
||||
await publishEvent(Event.TABLE_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(table: Table) {
|
||||
async function deleted(table: Table) {
|
||||
const properties: TableDeletedEvent = {
|
||||
tableId: table._id as string,
|
||||
}
|
||||
await publishEvent(Event.TABLE_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function exported(table: Table, format: TableExportFormat) {
|
||||
async function exported(table: Table, format: TableExportFormat) {
|
||||
const properties: TableExportedEvent = {
|
||||
tableId: table._id as string,
|
||||
format,
|
||||
|
@ -40,10 +39,17 @@ export async function exported(table: Table, format: TableExportFormat) {
|
|||
await publishEvent(Event.TABLE_EXPORTED, properties)
|
||||
}
|
||||
|
||||
export async function imported(table: Table, format: TableImportFormat) {
|
||||
async function imported(table: Table) {
|
||||
const properties: TableImportedEvent = {
|
||||
tableId: table._id as string,
|
||||
format,
|
||||
}
|
||||
await publishEvent(Event.TABLE_IMPORTED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
exported,
|
||||
imported,
|
||||
}
|
||||
|
|
|
@ -15,21 +15,21 @@ import {
|
|||
UserUpdatedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function created(user: User, timestamp?: number) {
|
||||
async function created(user: User, timestamp?: number) {
|
||||
const properties: UserCreatedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(user: User) {
|
||||
async function updated(user: User) {
|
||||
const properties: UserUpdatedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(user: User) {
|
||||
async function deleted(user: User) {
|
||||
const properties: UserDeletedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export async function deleted(user: User) {
|
|||
|
||||
// PERMISSIONS
|
||||
|
||||
export async function permissionAdminAssigned(user: User, timestamp?: number) {
|
||||
async function permissionAdminAssigned(user: User, timestamp?: number) {
|
||||
const properties: UserPermissionAssignedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
|
@ -49,17 +49,14 @@ export async function permissionAdminAssigned(user: User, timestamp?: number) {
|
|||
)
|
||||
}
|
||||
|
||||
export async function permissionAdminRemoved(user: User) {
|
||||
async function permissionAdminRemoved(user: User) {
|
||||
const properties: UserPermissionRemovedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties)
|
||||
}
|
||||
|
||||
export async function permissionBuilderAssigned(
|
||||
user: User,
|
||||
timestamp?: number
|
||||
) {
|
||||
async function permissionBuilderAssigned(user: User, timestamp?: number) {
|
||||
const properties: UserPermissionAssignedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
|
@ -70,7 +67,7 @@ export async function permissionBuilderAssigned(
|
|||
)
|
||||
}
|
||||
|
||||
export async function permissionBuilderRemoved(user: User) {
|
||||
async function permissionBuilderRemoved(user: User) {
|
||||
const properties: UserPermissionRemovedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
|
@ -79,12 +76,12 @@ export async function permissionBuilderRemoved(user: User) {
|
|||
|
||||
// INVITE
|
||||
|
||||
export async function invited() {
|
||||
async function invited() {
|
||||
const properties: UserInvitedEvent = {}
|
||||
await publishEvent(Event.USER_INVITED, properties)
|
||||
}
|
||||
|
||||
export async function inviteAccepted(user: User) {
|
||||
async function inviteAccepted(user: User) {
|
||||
const properties: UserInviteAcceptedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
|
@ -93,30 +90,46 @@ export async function inviteAccepted(user: User) {
|
|||
|
||||
// PASSWORD
|
||||
|
||||
export async function passwordForceReset(user: User) {
|
||||
async function passwordForceReset(user: User) {
|
||||
const properties: UserPasswordForceResetEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_PASSWORD_FORCE_RESET, properties)
|
||||
}
|
||||
|
||||
export async function passwordUpdated(user: User) {
|
||||
async function passwordUpdated(user: User) {
|
||||
const properties: UserPasswordUpdatedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_PASSWORD_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function passwordResetRequested(user: User) {
|
||||
async function passwordResetRequested(user: User) {
|
||||
const properties: UserPasswordResetRequestedEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_PASSWORD_RESET_REQUESTED, properties)
|
||||
}
|
||||
|
||||
export async function passwordReset(user: User) {
|
||||
async function passwordReset(user: User) {
|
||||
const properties: UserPasswordResetEvent = {
|
||||
userId: user._id as string,
|
||||
}
|
||||
await publishEvent(Event.USER_PASSWORD_RESET, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
permissionAdminAssigned,
|
||||
permissionAdminRemoved,
|
||||
permissionBuilderAssigned,
|
||||
permissionBuilderRemoved,
|
||||
invited,
|
||||
inviteAccepted,
|
||||
passwordForceReset,
|
||||
passwordUpdated,
|
||||
passwordResetRequested,
|
||||
passwordReset,
|
||||
}
|
||||
|
|
|
@ -19,28 +19,28 @@ import {
|
|||
|
||||
/* eslint-disable */
|
||||
|
||||
export async function created(view: View, timestamp?: string | number) {
|
||||
async function created(view: View, timestamp?: string | number) {
|
||||
const properties: ViewCreatedEvent = {
|
||||
tableId: view.tableId,
|
||||
}
|
||||
await publishEvent(Event.VIEW_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function updated(view: View) {
|
||||
async function updated(view: View) {
|
||||
const properties: ViewUpdatedEvent = {
|
||||
tableId: view.tableId,
|
||||
}
|
||||
await publishEvent(Event.VIEW_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function deleted(view: View) {
|
||||
async function deleted(view: View) {
|
||||
const properties: ViewDeletedEvent = {
|
||||
tableId: view.tableId,
|
||||
}
|
||||
await publishEvent(Event.VIEW_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function exported(table: Table, format: TableExportFormat) {
|
||||
async function exported(table: Table, format: TableExportFormat) {
|
||||
const properties: ViewExportedEvent = {
|
||||
tableId: table._id as string,
|
||||
format,
|
||||
|
@ -48,31 +48,28 @@ export async function exported(table: Table, format: TableExportFormat) {
|
|||
await publishEvent(Event.VIEW_EXPORTED, properties)
|
||||
}
|
||||
|
||||
export async function filterCreated(view: View, timestamp?: string | number) {
|
||||
async function filterCreated(view: View, timestamp?: string | number) {
|
||||
const properties: ViewFilterCreatedEvent = {
|
||||
tableId: view.tableId,
|
||||
}
|
||||
await publishEvent(Event.VIEW_FILTER_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function filterUpdated(view: View) {
|
||||
async function filterUpdated(view: View) {
|
||||
const properties: ViewFilterUpdatedEvent = {
|
||||
tableId: view.tableId,
|
||||
}
|
||||
await publishEvent(Event.VIEW_FILTER_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function filterDeleted(view: View) {
|
||||
async function filterDeleted(view: View) {
|
||||
const properties: ViewFilterDeletedEvent = {
|
||||
tableId: view.tableId,
|
||||
}
|
||||
await publishEvent(Event.VIEW_FILTER_DELETED, properties)
|
||||
}
|
||||
|
||||
export async function calculationCreated(
|
||||
view: View,
|
||||
timestamp?: string | number
|
||||
) {
|
||||
async function calculationCreated(view: View, timestamp?: string | number) {
|
||||
const properties: ViewCalculationCreatedEvent = {
|
||||
tableId: view.tableId,
|
||||
calculation: view.calculation as ViewCalculation,
|
||||
|
@ -80,7 +77,7 @@ export async function calculationCreated(
|
|||
await publishEvent(Event.VIEW_CALCULATION_CREATED, properties, timestamp)
|
||||
}
|
||||
|
||||
export async function calculationUpdated(view: View) {
|
||||
async function calculationUpdated(view: View) {
|
||||
const properties: ViewCalculationUpdatedEvent = {
|
||||
tableId: view.tableId,
|
||||
calculation: view.calculation as ViewCalculation,
|
||||
|
@ -88,10 +85,23 @@ export async function calculationUpdated(view: View) {
|
|||
await publishEvent(Event.VIEW_CALCULATION_UPDATED, properties)
|
||||
}
|
||||
|
||||
export async function calculationDeleted(existingView: View) {
|
||||
async function calculationDeleted(existingView: View) {
|
||||
const properties: ViewCalculationDeletedEvent = {
|
||||
tableId: existingView.tableId,
|
||||
calculation: existingView.calculation as ViewCalculation,
|
||||
}
|
||||
await publishEvent(Event.VIEW_CALCULATION_DELETED, properties)
|
||||
}
|
||||
|
||||
export default {
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
exported,
|
||||
filterCreated,
|
||||
filterUpdated,
|
||||
filterDeleted,
|
||||
calculationCreated,
|
||||
calculationUpdated,
|
||||
calculationDeleted,
|
||||
}
|
||||
|
|
|
@ -1,68 +1,42 @@
|
|||
import errors from "./errors"
|
||||
const errorClasses = errors.errors
|
||||
import * as events from "./events"
|
||||
import * as migrations from "./migrations"
|
||||
import * as users from "./users"
|
||||
import * as roles from "./security/roles"
|
||||
import * as permissions from "./security/permissions"
|
||||
import * as accounts from "./cloud/accounts"
|
||||
import * as installation from "./installation"
|
||||
import env from "./environment"
|
||||
import * as tenancy from "./tenancy"
|
||||
import * as featureFlags from "./featureFlags"
|
||||
import * as sessions from "./security/sessions"
|
||||
import * as deprovisioning from "./context/deprovision"
|
||||
import * as auth from "./auth"
|
||||
import * as constants from "./constants"
|
||||
import * as logging from "./logging"
|
||||
import * as pino from "./pino"
|
||||
import * as middleware from "./middleware"
|
||||
import * as plugins from "./plugin"
|
||||
import * as encryption from "./security/encryption"
|
||||
import * as queue from "./queue"
|
||||
import * as db from "./db"
|
||||
import * as context from "./context"
|
||||
import * as cache from "./cache"
|
||||
import * as objectStore from "./objectStore"
|
||||
import * as redis from "./redis"
|
||||
import * as utils from "./utils"
|
||||
export * as events from "./events"
|
||||
export * as migrations from "./migrations"
|
||||
export * as users from "./users"
|
||||
export * as roles from "./security/roles"
|
||||
export * as permissions from "./security/permissions"
|
||||
export * as accounts from "./cloud/accounts"
|
||||
export * as installation from "./installation"
|
||||
export * as tenancy from "./tenancy"
|
||||
export * as featureFlags from "./featureFlags"
|
||||
export * as sessions from "./security/sessions"
|
||||
export * as deprovisioning from "./context/deprovision"
|
||||
export * as auth from "./auth"
|
||||
export * as constants from "./constants"
|
||||
export * as logging from "./logging"
|
||||
export * as middleware from "./middleware"
|
||||
export * as plugins from "./plugin"
|
||||
export * as encryption from "./security/encryption"
|
||||
export * as queue from "./queue"
|
||||
export * as db from "./db"
|
||||
export * as context from "./context"
|
||||
export * as cache from "./cache"
|
||||
export * as objectStore from "./objectStore"
|
||||
export * as redis from "./redis"
|
||||
export * as utils from "./utils"
|
||||
export * as errors from "./errors"
|
||||
export { default as env } from "./environment"
|
||||
|
||||
const init = (opts: any = {}) => {
|
||||
// expose error classes directly
|
||||
export * from "./errors"
|
||||
|
||||
// expose constants directly
|
||||
export * from "./constants"
|
||||
|
||||
// expose inner locks from redis directly
|
||||
import * as redis from "./redis"
|
||||
export const locks = redis.redlock
|
||||
|
||||
// expose package init function
|
||||
import * as db from "./db"
|
||||
export const init = (opts: any = {}) => {
|
||||
db.init(opts.db)
|
||||
}
|
||||
|
||||
const core = {
|
||||
init,
|
||||
db,
|
||||
...constants,
|
||||
redis,
|
||||
locks: redis.redlock,
|
||||
objectStore,
|
||||
utils,
|
||||
users,
|
||||
cache,
|
||||
auth,
|
||||
constants,
|
||||
migrations,
|
||||
env,
|
||||
accounts,
|
||||
tenancy,
|
||||
context,
|
||||
featureFlags,
|
||||
events,
|
||||
sessions,
|
||||
deprovisioning,
|
||||
installation,
|
||||
errors,
|
||||
logging,
|
||||
roles,
|
||||
plugins,
|
||||
...pino,
|
||||
...errorClasses,
|
||||
middleware,
|
||||
encryption,
|
||||
queue,
|
||||
permissions,
|
||||
}
|
||||
|
||||
export = core
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
import { Header } from "./constants"
|
||||
import env from "./environment"
|
||||
const correlator = require("correlation-id")
|
||||
import { Options } from "pino-http"
|
||||
import { IncomingMessage } from "http"
|
||||
|
||||
const NonErrors = ["AccountError"]
|
||||
|
||||
function isSuppressed(e?: any) {
|
||||
|
@ -29,8 +35,26 @@ export function logWarn(message: string) {
|
|||
console.warn(`bb-warn: ${message}`)
|
||||
}
|
||||
|
||||
export default {
|
||||
logAlert,
|
||||
logAlertWithInfo,
|
||||
logWarn,
|
||||
export function pinoSettings(): Options {
|
||||
return {
|
||||
prettyPrint: {
|
||||
levelFirst: true,
|
||||
},
|
||||
genReqId: correlator.getId,
|
||||
level: env.LOG_LEVEL || "error",
|
||||
autoLogging: {
|
||||
ignore: (req: IncomingMessage) => !!req.url?.includes("/health"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const setCorrelationHeader = (headers: any) => {
|
||||
const correlationId = correlator.getId()
|
||||
if (correlationId) {
|
||||
headers[Header.CORRELATION_ID] = correlationId
|
||||
}
|
||||
}
|
||||
|
||||
export const correlation = {
|
||||
setHeader: setCorrelationHeader,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BBContext } from "@budibase/types"
|
||||
|
||||
export = async (ctx: BBContext, next: any) => {
|
||||
export default async (ctx: BBContext, next: any) => {
|
||||
if (
|
||||
!ctx.internal &&
|
||||
(!ctx.user || !ctx.user.admin || !ctx.user.admin.global)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BBContext } from "@budibase/types"
|
||||
|
||||
export = async (ctx: BBContext | any, next: any) => {
|
||||
export default async (ctx: BBContext | any, next: any) => {
|
||||
// Placeholder for audit log middleware
|
||||
return next()
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ async function checkApiKey(apiKey: string, populateUser?: Function) {
|
|||
* The tenancy modules should not be used here and it should be assumed that the tenancy context
|
||||
* has not yet been populated.
|
||||
*/
|
||||
export = function (
|
||||
export default function (
|
||||
noAuthPatterns: EndpointMatcher[] = [],
|
||||
opts: { publicAllowed?: boolean; populateUser?: Function } = {
|
||||
publicAllowed: false,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BBContext } from "@budibase/types"
|
||||
|
||||
export = async (ctx: BBContext, next: any) => {
|
||||
export default async (ctx: BBContext, next: any) => {
|
||||
if (
|
||||
!ctx.internal &&
|
||||
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BBContext } from "@budibase/types"
|
||||
|
||||
export = async (ctx: BBContext, next: any) => {
|
||||
export default async (ctx: BBContext, next: any) => {
|
||||
if (
|
||||
!ctx.internal &&
|
||||
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global) &&
|
||||
|
|
|
@ -32,7 +32,7 @@ const INCLUDED_CONTENT_TYPES = [
|
|||
* https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern
|
||||
*
|
||||
*/
|
||||
export = function (
|
||||
export default function (
|
||||
opts: { noCsrfPatterns: EndpointMatcher[] } = { noCsrfPatterns: [] }
|
||||
) {
|
||||
const noCsrfOptions = buildMatcherRegex(opts.noCsrfPatterns)
|
||||
|
|
|
@ -1,38 +1,19 @@
|
|||
import * as jwt from "./passport/jwt"
|
||||
import * as local from "./passport/local"
|
||||
import * as google from "./passport/google"
|
||||
import * as oidc from "./passport/oidc"
|
||||
import { authError, ssoCallbackUrl } from "./passport/utils"
|
||||
import authenticated from "./authenticated"
|
||||
import auditLog from "./auditLog"
|
||||
import tenancy from "./tenancy"
|
||||
import internalApi from "./internalApi"
|
||||
export * as jwt from "./passport/jwt"
|
||||
export * as local from "./passport/local"
|
||||
export * as google from "./passport/google"
|
||||
export * as oidc from "./passport/oidc"
|
||||
import * as datasourceGoogle from "./passport/datasource/google"
|
||||
import csrf from "./csrf"
|
||||
import adminOnly from "./adminOnly"
|
||||
import builderOrAdmin from "./builderOrAdmin"
|
||||
import builderOnly from "./builderOnly"
|
||||
import * as joiValidator from "./joi-validator"
|
||||
|
||||
const pkg = {
|
||||
google,
|
||||
oidc,
|
||||
jwt,
|
||||
local,
|
||||
authenticated,
|
||||
auditLog,
|
||||
tenancy,
|
||||
authError,
|
||||
internalApi,
|
||||
ssoCallbackUrl,
|
||||
datasource: {
|
||||
google: datasourceGoogle,
|
||||
},
|
||||
csrf,
|
||||
adminOnly,
|
||||
builderOnly,
|
||||
builderOrAdmin,
|
||||
joiValidator,
|
||||
export const datasource = {
|
||||
google: datasourceGoogle,
|
||||
}
|
||||
|
||||
export = pkg
|
||||
export { authError, ssoCallbackUrl } from "./passport/utils"
|
||||
export { default as authenticated } from "./authenticated"
|
||||
export { default as auditLog } from "./auditLog"
|
||||
export { default as tenancy } from "./tenancy"
|
||||
export { default as internalApi } from "./internalApi"
|
||||
export { default as csrf } from "./csrf"
|
||||
export { default as adminOnly } from "./adminOnly"
|
||||
export { default as builderOrAdmin } from "./builderOrAdmin"
|
||||
export { default as builderOnly } from "./builderOnly"
|
||||
export { default as logging } from "./logging"
|
||||
export * as joiValidator from "./joi-validator"
|
||||
|
|
|
@ -5,7 +5,7 @@ import { BBContext } from "@budibase/types"
|
|||
/**
|
||||
* API Key only endpoint.
|
||||
*/
|
||||
export = async (ctx: BBContext, next: any) => {
|
||||
export default async (ctx: BBContext, next: any) => {
|
||||
const apiKey = ctx.request.headers[Header.API_KEY]
|
||||
if (apiKey !== env.INTERNAL_API_KEY) {
|
||||
ctx.throw(403, "Unauthorized")
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
const correlator = require("correlation-id")
|
||||
import { Header } from "../constants"
|
||||
import { v4 as uuid } from "uuid"
|
||||
import * as context from "../context"
|
||||
|
||||
const debug = console.warn
|
||||
const trace = console.trace
|
||||
const log = console.log
|
||||
const info = console.info
|
||||
const warn = console.warn
|
||||
const error = console.error
|
||||
|
||||
const getTenantId = () => {
|
||||
let tenantId
|
||||
try {
|
||||
tenantId = context.getTenantId()
|
||||
} catch (e: any) {
|
||||
// do nothing
|
||||
}
|
||||
return tenantId
|
||||
}
|
||||
|
||||
const getAppId = () => {
|
||||
let appId
|
||||
try {
|
||||
appId = context.getAppId()
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
return appId
|
||||
}
|
||||
|
||||
const getIdentityId = () => {
|
||||
let identityId
|
||||
try {
|
||||
const identity = context.getIdentity()
|
||||
identityId = identity?._id
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
return identityId
|
||||
}
|
||||
|
||||
const print = (fn: any, data: any[]) => {
|
||||
let message = ""
|
||||
|
||||
const correlationId = correlator.getId()
|
||||
if (correlationId) {
|
||||
message = message + `[correlationId=${correlator.getId()}]`
|
||||
}
|
||||
|
||||
const tenantId = getTenantId()
|
||||
if (tenantId) {
|
||||
message = message + ` [tenantId=${tenantId}]`
|
||||
}
|
||||
|
||||
const appId = getAppId()
|
||||
if (appId) {
|
||||
message = message + ` [appId=${appId}]`
|
||||
}
|
||||
|
||||
const identityId = getIdentityId()
|
||||
if (identityId) {
|
||||
message = message + ` [identityId=${identityId}]`
|
||||
}
|
||||
|
||||
fn(message, data)
|
||||
}
|
||||
|
||||
const logging = (ctx: any, next: any) => {
|
||||
// use the provided correlation id header if present
|
||||
let correlationId = ctx.headers[Header.CORRELATION_ID]
|
||||
if (!correlationId) {
|
||||
correlationId = uuid()
|
||||
}
|
||||
|
||||
return correlator.withId(correlationId, () => {
|
||||
console.debug = data => print(debug, data)
|
||||
console.trace = data => print(trace, data)
|
||||
console.log = data => print(log, data)
|
||||
console.info = data => print(info, data)
|
||||
console.warn = data => print(warn, data)
|
||||
console.error = data => print(error, data)
|
||||
return next()
|
||||
})
|
||||
}
|
||||
|
||||
export default logging
|
|
@ -2,7 +2,6 @@ import fetch from "node-fetch"
|
|||
import { authenticateThirdParty, SaveUserFunction } from "./third-party-common"
|
||||
import { ssoCallbackUrl } from "./utils"
|
||||
import {
|
||||
Config,
|
||||
ConfigType,
|
||||
OIDCInnerCfg,
|
||||
Database,
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
TenantResolutionStrategy,
|
||||
} from "@budibase/types"
|
||||
|
||||
export = function (
|
||||
export default function (
|
||||
allowQueryStringPatterns: EndpointMatcher[],
|
||||
noTenancyPatterns: EndpointMatcher[],
|
||||
opts: { noTenancyRequired?: boolean } = { noTenancyRequired: false }
|
||||
|
|
|
@ -88,7 +88,7 @@ export const runMigration = async (
|
|||
|
||||
await doWithDB(dbName, async (db: any) => {
|
||||
try {
|
||||
const doc = await exports.getMigrationsDoc(db)
|
||||
const doc = await getMigrationsDoc(db)
|
||||
|
||||
// the migration has already been run
|
||||
if (doc[migrationName]) {
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import env from "./environment"
|
||||
|
||||
export function pinoSettings() {
|
||||
return {
|
||||
prettyPrint: {
|
||||
levelFirst: true,
|
||||
},
|
||||
level: env.LOG_LEVEL || "error",
|
||||
autoLogging: {
|
||||
ignore: (req: { url: string }) => req.url.includes("/health"),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -137,4 +137,4 @@ class InMemoryQueue {
|
|||
}
|
||||
}
|
||||
|
||||
export = InMemoryQueue
|
||||
export default InMemoryQueue
|
||||
|
|
|
@ -276,4 +276,4 @@ class RedisWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
export = RedisWrapper
|
||||
export default RedisWrapper
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const redis = require("../redis/init")
|
||||
const { v4: uuidv4 } = require("uuid")
|
||||
const { logWarn } = require("../logging")
|
||||
const env = require("../environment")
|
||||
import env from "../environment"
|
||||
import {
|
||||
Session,
|
||||
ScannedSession,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { structures } from "../../../tests"
|
||||
import * as utils from "../../utils"
|
||||
import * as events from "../../events"
|
||||
import { DEFAULT_TENANT_ID } from "../../constants"
|
||||
import * as db from "../../db"
|
||||
import { DEFAULT_TENANT_ID, Header } from "../../constants"
|
||||
import { doInTenant } from "../../context"
|
||||
|
||||
describe("utils", () => {
|
||||
|
@ -14,4 +15,95 @@ describe("utils", () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getAppIdFromCtx", () => {
|
||||
it("gets appId from header", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const expected = db.generateAppID()
|
||||
ctx.request.headers = {
|
||||
[Header.APP_ID]: expected,
|
||||
}
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
it("gets appId from body", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const expected = db.generateAppID()
|
||||
ctx.request.body = {
|
||||
appId: expected,
|
||||
}
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
it("gets appId from path", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const expected = db.generateAppID()
|
||||
ctx.path = `/apps/${expected}`
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
it("gets appId from url", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const expected = db.generateAppID()
|
||||
const app = structures.apps.app(expected)
|
||||
|
||||
// set custom url
|
||||
const appUrl = "custom-url"
|
||||
app.url = `/${appUrl}`
|
||||
ctx.path = `/app/${appUrl}`
|
||||
|
||||
// save the app
|
||||
const database = db.getDB(expected)
|
||||
await database.put(app)
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
it("doesn't get appId from url when previewing", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const appId = db.generateAppID()
|
||||
const app = structures.apps.app(appId)
|
||||
|
||||
// set custom url
|
||||
const appUrl = "preview"
|
||||
app.url = `/${appUrl}`
|
||||
ctx.path = `/app/${appUrl}`
|
||||
|
||||
// save the app
|
||||
const database = db.getDB(appId)
|
||||
await database.put(app)
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(undefined)
|
||||
})
|
||||
|
||||
it("gets appId from referer", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const expected = db.generateAppID()
|
||||
ctx.request.headers = {
|
||||
referer: `http://test.com/builder/app/${expected}/design/screen_123/screens`,
|
||||
}
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
it("doesn't get appId from referer when not builder", async () => {
|
||||
const ctx = structures.koa.newContext()
|
||||
const appId = db.generateAppID()
|
||||
ctx.request.headers = {
|
||||
referer: `http://test.com/foo/app/${appId}/bar`,
|
||||
}
|
||||
|
||||
const actual = await utils.getAppIdFromCtx(ctx)
|
||||
expect(actual).toBe(undefined)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -25,13 +25,16 @@ const jwt = require("jsonwebtoken")
|
|||
const APP_PREFIX = DocumentType.APP + SEPARATOR
|
||||
const PROD_APP_PREFIX = "/app/"
|
||||
|
||||
const BUILDER_PREVIEW_PATH = "/app/preview"
|
||||
const BUILDER_REFERER_PREFIX = "/builder/app/"
|
||||
|
||||
function confirmAppId(possibleAppId: string | undefined) {
|
||||
return possibleAppId && possibleAppId.startsWith(APP_PREFIX)
|
||||
? possibleAppId
|
||||
: undefined
|
||||
}
|
||||
|
||||
async function resolveAppUrl(ctx: Ctx) {
|
||||
export async function resolveAppUrl(ctx: Ctx) {
|
||||
const appUrl = ctx.path.split("/")[2]
|
||||
let possibleAppUrl = `/${appUrl.toLowerCase()}`
|
||||
|
||||
|
@ -75,7 +78,7 @@ export function isServingApp(ctx: Ctx) {
|
|||
*/
|
||||
export async function getAppIdFromCtx(ctx: Ctx) {
|
||||
// look in headers
|
||||
const options = [ctx.headers[Header.APP_ID]]
|
||||
const options = [ctx.request.headers[Header.APP_ID]]
|
||||
let appId
|
||||
for (let option of options) {
|
||||
appId = confirmAppId(option as string)
|
||||
|
@ -95,15 +98,23 @@ export async function getAppIdFromCtx(ctx: Ctx) {
|
|||
appId = confirmAppId(pathId)
|
||||
}
|
||||
|
||||
// look in the referer
|
||||
const refererId = parseAppIdFromUrl(ctx.request.headers.referer)
|
||||
if (!appId && refererId) {
|
||||
appId = confirmAppId(refererId)
|
||||
// lookup using custom url - prod apps only
|
||||
// filter out the builder preview path which collides with the prod app path
|
||||
// to ensure we don't load all apps excessively
|
||||
const isBuilderPreview = ctx.path.startsWith(BUILDER_PREVIEW_PATH)
|
||||
const isViewingProdApp =
|
||||
ctx.path.startsWith(PROD_APP_PREFIX) && !isBuilderPreview
|
||||
if (!appId && isViewingProdApp) {
|
||||
appId = confirmAppId(await resolveAppUrl(ctx))
|
||||
}
|
||||
|
||||
// look in the url - prod app
|
||||
if (!appId && ctx.path.startsWith(PROD_APP_PREFIX)) {
|
||||
appId = confirmAppId(await resolveAppUrl(ctx))
|
||||
// look in the referer - builder only
|
||||
// make sure this is performed after prod app url resolution, in case the
|
||||
// referer header is present from a builder redirect
|
||||
const referer = ctx.request.headers.referer
|
||||
if (!appId && referer?.includes(BUILDER_REFERER_PREFIX)) {
|
||||
const refererId = parseAppIdFromUrl(ctx.request.headers.referer)
|
||||
appId = confirmAppId(refererId)
|
||||
}
|
||||
|
||||
return appId
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
export const getAccount = jest.fn()
|
||||
export const getAccountByTenantId = jest.fn()
|
||||
export const getStatus = jest.fn()
|
||||
const mockGetAccount = jest.fn()
|
||||
const mockGetAccountByTenantId = jest.fn()
|
||||
const mockGetStatus = jest.fn()
|
||||
|
||||
jest.mock("../../../src/cloud/accounts", () => ({
|
||||
getAccount,
|
||||
getAccountByTenantId,
|
||||
getStatus,
|
||||
getAccount: mockGetAccount,
|
||||
getAccountByTenantId: mockGetAccountByTenantId,
|
||||
getStatus: mockGetStatus,
|
||||
}))
|
||||
|
||||
export const getAccount = mockGetAccount
|
||||
export const getAccountByTenantId = mockGetAccountByTenantId
|
||||
export const getStatus = mockGetStatus
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
const processors = require("../../../src/events/processors")
|
||||
import * as processors from "../../../src/events/processors"
|
||||
import * as events from "../../../src/events"
|
||||
|
||||
jest.spyOn(processors.analyticsProcessor, "processEvent")
|
||||
|
||||
const events = require("../../../src/events")
|
||||
|
||||
jest.spyOn(events.identification, "identifyTenantGroup")
|
||||
jest.spyOn(events.identification, "identifyUser")
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { generator } from "."
|
||||
import { App } from "@budibase/types"
|
||||
import { DEFAULT_TENANT_ID, DocumentType } from "../../../src/constants"
|
||||
|
||||
export function app(id: string): App {
|
||||
return {
|
||||
_id: DocumentType.APP_METADATA,
|
||||
appId: id,
|
||||
type: "",
|
||||
version: "0.0.1",
|
||||
componentLibraries: [],
|
||||
name: generator.name(),
|
||||
url: `/custom-url`,
|
||||
instance: {
|
||||
_id: id,
|
||||
},
|
||||
tenantId: DEFAULT_TENANT_ID,
|
||||
status: "",
|
||||
template: undefined,
|
||||
}
|
||||
}
|
|
@ -3,7 +3,8 @@ export * from "./common"
|
|||
import Chance from "chance"
|
||||
export const generator = new Chance()
|
||||
|
||||
export * as koa from "./koa"
|
||||
export * as accounts from "./accounts"
|
||||
export * as apps from "./apps"
|
||||
export * as koa from "./koa"
|
||||
export * as licenses from "./licenses"
|
||||
export * as plugins from "./plugins"
|
||||
|
|
|
@ -5,9 +5,11 @@ export const newContext = (): BBContext => {
|
|||
const ctx = createMockContext()
|
||||
return {
|
||||
...ctx,
|
||||
path: "/",
|
||||
cookies: createMockCookies(),
|
||||
request: {
|
||||
...ctx.request,
|
||||
headers: {},
|
||||
body: {},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"declaration": true,
|
||||
"types": [ "node", "jest" ],
|
||||
"outDir": "dist",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.js",
|
||||
|
@ -22,6 +23,7 @@
|
|||
"node_modules",
|
||||
"dist",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.js"
|
||||
"**/*.spec.js",
|
||||
"__mocks__"
|
||||
]
|
||||
}
|
|
@ -12,6 +12,6 @@
|
|||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
"dist",
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "2.2.12-alpha.2",
|
||||
"version": "2.2.12-alpha.32",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
||||
"@budibase/string-templates": "2.2.12-alpha.2",
|
||||
"@budibase/string-templates": "2.2.12-alpha.32",
|
||||
"@spectrum-css/actionbutton": "1.0.1",
|
||||
"@spectrum-css/actiongroup": "1.0.1",
|
||||
"@spectrum-css/avatar": "3.0.2",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
const ignoredClasses = [".flatpickr-calendar", ".modal-container"]
|
||||
const ignoredClasses = [".flatpickr-calendar"]
|
||||
let clickHandlers = []
|
||||
|
||||
/**
|
||||
* Handle a body click event
|
||||
*/
|
||||
const handleClick = event => {
|
||||
// Ignore click if needed
|
||||
// Ignore click if this is an ignored class
|
||||
for (let className of ignoredClasses) {
|
||||
if (event.target.closest(className)) {
|
||||
return
|
||||
|
@ -14,9 +14,18 @@ const handleClick = event => {
|
|||
|
||||
// Process handlers
|
||||
clickHandlers.forEach(handler => {
|
||||
if (!handler.element.contains(event.target)) {
|
||||
handler.callback?.(event)
|
||||
if (handler.element.contains(event.target)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Ignore clicks for modals, unless the handler is registered from a modal
|
||||
const sourceInModal = handler.element.closest(".spectrum-Modal") != null
|
||||
const clickInModal = event.target.closest(".spectrum-Modal") != null
|
||||
if (clickInModal && !sourceInModal) {
|
||||
return
|
||||
}
|
||||
|
||||
handler.callback?.(event)
|
||||
})
|
||||
}
|
||||
document.documentElement.addEventListener("click", handleClick, true)
|
||||
|
|
|
@ -1,75 +1,68 @@
|
|||
export default function positionDropdown(element, { anchor, align, maxWidth }) {
|
||||
let positionSide = "top"
|
||||
let maxHeight = 0
|
||||
let dimensions = getDimensions(anchor)
|
||||
export default function positionDropdown(
|
||||
element,
|
||||
{ anchor, align, maxWidth, useAnchorWidth }
|
||||
) {
|
||||
const update = () => {
|
||||
const anchorBounds = anchor.getBoundingClientRect()
|
||||
const elementBounds = element.getBoundingClientRect()
|
||||
let styles = {
|
||||
maxHeight: null,
|
||||
minWidth: null,
|
||||
maxWidth,
|
||||
left: null,
|
||||
top: null,
|
||||
}
|
||||
|
||||
function getDimensions() {
|
||||
const {
|
||||
bottom,
|
||||
top: spaceAbove,
|
||||
left,
|
||||
width,
|
||||
} = anchor.getBoundingClientRect()
|
||||
const spaceBelow = window.innerHeight - bottom
|
||||
const containerRect = element.getBoundingClientRect()
|
||||
|
||||
let y
|
||||
|
||||
if (spaceAbove > spaceBelow) {
|
||||
positionSide = "bottom"
|
||||
maxHeight = spaceAbove - 20
|
||||
y = window.innerHeight - spaceAbove + 5
|
||||
// Determine vertical styles
|
||||
if (window.innerHeight - anchorBounds.bottom < 100) {
|
||||
styles.top = anchorBounds.top - elementBounds.height - 5
|
||||
} else {
|
||||
positionSide = "top"
|
||||
y = bottom + 5
|
||||
maxHeight = spaceBelow - 20
|
||||
styles.top = anchorBounds.bottom + 5
|
||||
styles.maxHeight = window.innerHeight - anchorBounds.bottom - 20
|
||||
}
|
||||
|
||||
return {
|
||||
[positionSide]: y,
|
||||
left,
|
||||
width,
|
||||
containerWidth: containerRect.width,
|
||||
// Determine horizontal styles
|
||||
if (!maxWidth && useAnchorWidth) {
|
||||
styles.maxWidth = anchorBounds.width
|
||||
}
|
||||
if (useAnchorWidth) {
|
||||
styles.minWidth = anchorBounds.width
|
||||
}
|
||||
if (align === "right") {
|
||||
styles.left = anchorBounds.left + anchorBounds.width - elementBounds.width
|
||||
} else if (align === "right-side") {
|
||||
styles.left = anchorBounds.left + anchorBounds.width
|
||||
} else {
|
||||
styles.left = anchorBounds.left
|
||||
}
|
||||
|
||||
// Apply styles
|
||||
Object.entries(styles).forEach(([style, value]) => {
|
||||
if (value) {
|
||||
element.style[style] = `${value.toFixed(0)}px`
|
||||
} else {
|
||||
element.style[style] = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function calcLeftPosition() {
|
||||
let left
|
||||
|
||||
if (align == "right") {
|
||||
left = dimensions.left + dimensions.width - dimensions.containerWidth
|
||||
} else if (align == "right-side") {
|
||||
left = dimensions.left + dimensions.width
|
||||
} else {
|
||||
left = dimensions.left
|
||||
}
|
||||
|
||||
return left
|
||||
}
|
||||
|
||||
// Apply initial styles which don't need to change
|
||||
element.style.position = "absolute"
|
||||
element.style.zIndex = "9999"
|
||||
if (maxWidth) {
|
||||
element.style.maxWidth = `${maxWidth}px`
|
||||
}
|
||||
element.style.minWidth = `${dimensions.width}px`
|
||||
element.style.maxHeight = `${maxHeight.toFixed(0)}px`
|
||||
element.style.transformOrigin = `center ${positionSide}`
|
||||
element.style[positionSide] = `${dimensions[positionSide]}px`
|
||||
element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px`
|
||||
|
||||
// Observe both anchor and element and resize the popover as appropriate
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
entries.forEach(() => {
|
||||
dimensions = getDimensions()
|
||||
element.style[positionSide] = `${dimensions[positionSide]}px`
|
||||
element.style.left = `${calcLeftPosition(dimensions).toFixed(0)}px`
|
||||
})
|
||||
entries.forEach(update)
|
||||
})
|
||||
resizeObserver.observe(anchor)
|
||||
resizeObserver.observe(element)
|
||||
|
||||
document.addEventListener("scroll", update, true)
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
resizeObserver.disconnect()
|
||||
document.removeEventListener("scroll", update, true)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,5 +58,6 @@
|
|||
overflow: hidden;
|
||||
user-select: none;
|
||||
text-transform: uppercase;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
export let active = false
|
||||
export let tooltip = undefined
|
||||
export let dataCy
|
||||
export let newStyles = false
|
||||
export let newStyles = true
|
||||
|
||||
let showTooltip = false
|
||||
</script>
|
||||
|
@ -28,6 +28,7 @@
|
|||
class:spectrum-Button--quiet={quiet}
|
||||
class:new-styles={newStyles}
|
||||
class:active
|
||||
class:disabled
|
||||
class="spectrum-Button spectrum-Button--size{size.toUpperCase()}"
|
||||
{disabled}
|
||||
data-cy={dataCy}
|
||||
|
@ -108,7 +109,10 @@
|
|||
border-color: transparent;
|
||||
color: var(--spectrum-global-color-gray-900);
|
||||
}
|
||||
.spectrum-Button--secondary.new-styles:hover {
|
||||
.spectrum-Button--secondary.new-styles:not(.disabled):hover {
|
||||
background: var(--spectrum-global-color-gray-300);
|
||||
}
|
||||
.spectrum-Button--secondary.new-styles.disabled {
|
||||
color: var(--spectrum-global-color-gray-500);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
display: none;
|
||||
}
|
||||
.main {
|
||||
font-family: var(--font-sans);
|
||||
padding: var(--spacing-xl);
|
||||
}
|
||||
.main :global(textarea) {
|
||||
|
|
|
@ -264,7 +264,7 @@
|
|||
max-height: 100%;
|
||||
}
|
||||
:global(.flatpickr-calendar) {
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
.is-disabled {
|
||||
pointer-events: none !important;
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
import "@spectrum-css/picker/dist/index-vars.css"
|
||||
import "@spectrum-css/popover/dist/index-vars.css"
|
||||
import "@spectrum-css/menu/dist/index-vars.css"
|
||||
import { fly } from "svelte/transition"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import clickOutside from "../../Actions/click_outside"
|
||||
import Search from "./Search.svelte"
|
||||
import Icon from "../../Icon/Icon.svelte"
|
||||
import StatusLight from "../../StatusLight/StatusLight.svelte"
|
||||
import Popover from "../../Popover/Popover.svelte"
|
||||
|
||||
export let id = null
|
||||
export let disabled = false
|
||||
|
@ -33,7 +33,10 @@
|
|||
export let sort = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let searchTerm = null
|
||||
let button
|
||||
let popover
|
||||
|
||||
$: sortedOptions = getSortedOptions(options, getOptionLabel, sort)
|
||||
$: filteredOptions = getFilteredOptions(
|
||||
|
@ -42,7 +45,9 @@
|
|||
getOptionLabel
|
||||
)
|
||||
|
||||
const onClick = () => {
|
||||
const onClick = e => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
dispatch("click")
|
||||
if (readonly) {
|
||||
return
|
||||
|
@ -76,77 +81,119 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div use:clickOutside={() => (open = false)}>
|
||||
<button
|
||||
{id}
|
||||
class="spectrum-Picker spectrum-Picker--sizeM"
|
||||
class:spectrum-Picker--quiet={quiet}
|
||||
{disabled}
|
||||
class:is-invalid={!!error}
|
||||
class:is-open={open}
|
||||
aria-haspopup="listbox"
|
||||
on:click={onClick}
|
||||
>
|
||||
{#if fieldIcon}
|
||||
<span class="option-extra">
|
||||
<Icon name={fieldIcon} />
|
||||
</span>
|
||||
{/if}
|
||||
{#if fieldColour}
|
||||
<span class="option-extra">
|
||||
<StatusLight square color={fieldColour} />
|
||||
</span>
|
||||
{/if}
|
||||
<span
|
||||
class="spectrum-Picker-label"
|
||||
class:is-placeholder={isPlaceholder}
|
||||
class:auto-width={autoWidth}
|
||||
>
|
||||
{fieldText}
|
||||
<button
|
||||
{id}
|
||||
class="spectrum-Picker spectrum-Picker--sizeM"
|
||||
class:spectrum-Picker--quiet={quiet}
|
||||
{disabled}
|
||||
class:is-invalid={!!error}
|
||||
class:is-open={open}
|
||||
aria-haspopup="listbox"
|
||||
on:click={onClick}
|
||||
bind:this={button}
|
||||
>
|
||||
{#if fieldIcon}
|
||||
<span class="option-extra icon">
|
||||
<Icon size="S" name={fieldIcon} />
|
||||
</span>
|
||||
{#if error}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
aria-label="Folder"
|
||||
>
|
||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||
</svg>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if fieldColour}
|
||||
<span class="option-extra">
|
||||
<StatusLight square color={fieldColour} />
|
||||
</span>
|
||||
{/if}
|
||||
<span
|
||||
class="spectrum-Picker-label"
|
||||
class:is-placeholder={isPlaceholder}
|
||||
class:auto-width={autoWidth}
|
||||
>
|
||||
{fieldText}
|
||||
</span>
|
||||
{#if error}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
aria-label="Folder"
|
||||
>
|
||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||
<use xlink:href="#spectrum-icon-18-Alert" />
|
||||
</svg>
|
||||
</button>
|
||||
{#if open}
|
||||
<div
|
||||
transition:fly|local={{ y: -20, duration: 200 }}
|
||||
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"
|
||||
class:auto-width={autoWidth}
|
||||
>
|
||||
{#if autocomplete}
|
||||
<Search
|
||||
value={searchTerm}
|
||||
on:change={event => (searchTerm = event.detail)}
|
||||
{disabled}
|
||||
placeholder="Search"
|
||||
/>
|
||||
{/if}
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<use xlink:href="#spectrum-css-icon-Chevron100" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<Popover
|
||||
anchor={button}
|
||||
align="left"
|
||||
bind:this={popover}
|
||||
{open}
|
||||
on:close={() => (open = false)}
|
||||
useAnchorWidth={!autoWidth}
|
||||
maxWidth={autoWidth ? 400 : null}
|
||||
>
|
||||
<div
|
||||
class="popover-content"
|
||||
class:auto-width={autoWidth}
|
||||
use:clickOutside={() => (open = false)}
|
||||
>
|
||||
{#if autocomplete}
|
||||
<Search
|
||||
value={searchTerm}
|
||||
on:change={event => (searchTerm = event.detail)}
|
||||
{disabled}
|
||||
placeholder="Search"
|
||||
/>
|
||||
{/if}
|
||||
<ul class="spectrum-Menu" role="listbox">
|
||||
{#if placeholderOption}
|
||||
<li
|
||||
class="spectrum-Menu-item placeholder"
|
||||
class:is-selected={isPlaceholder}
|
||||
role="option"
|
||||
aria-selected="true"
|
||||
tabindex="0"
|
||||
on:click={() => onSelectOption(null)}
|
||||
>
|
||||
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span>
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||
</svg>
|
||||
</li>
|
||||
{/if}
|
||||
<ul class="spectrum-Menu" role="listbox">
|
||||
{#if placeholderOption}
|
||||
{#if filteredOptions.length}
|
||||
{#each filteredOptions as option, idx}
|
||||
<li
|
||||
class="spectrum-Menu-item placeholder"
|
||||
class:is-selected={isPlaceholder}
|
||||
class="spectrum-Menu-item"
|
||||
class:is-selected={isOptionSelected(getOptionValue(option, idx))}
|
||||
role="option"
|
||||
aria-selected="true"
|
||||
tabindex="0"
|
||||
on:click={() => onSelectOption(null)}
|
||||
on:click={() => onSelectOption(getOptionValue(option, idx))}
|
||||
class:is-disabled={!isOptionEnabled(option)}
|
||||
>
|
||||
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span>
|
||||
{#if getOptionIcon(option, idx)}
|
||||
<span class="option-extra icon">
|
||||
<Icon size="S" name={getOptionIcon(option, idx)} />
|
||||
</span>
|
||||
{/if}
|
||||
{#if getOptionColour(option, idx)}
|
||||
<span class="option-extra">
|
||||
<StatusLight square color={getOptionColour(option, idx)} />
|
||||
</span>
|
||||
{/if}
|
||||
<span class="spectrum-Menu-itemLabel">
|
||||
{getOptionLabel(option, idx)}
|
||||
</span>
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||
focusable="false"
|
||||
|
@ -155,61 +202,13 @@
|
|||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||
</svg>
|
||||
</li>
|
||||
{/if}
|
||||
{#if filteredOptions.length}
|
||||
{#each filteredOptions as option, idx}
|
||||
<li
|
||||
class="spectrum-Menu-item"
|
||||
class:is-selected={isOptionSelected(getOptionValue(option, idx))}
|
||||
role="option"
|
||||
aria-selected="true"
|
||||
tabindex="0"
|
||||
on:click={() => onSelectOption(getOptionValue(option, idx))}
|
||||
class:is-disabled={!isOptionEnabled(option)}
|
||||
>
|
||||
{#if getOptionIcon(option, idx)}
|
||||
<span class="option-extra">
|
||||
<Icon name={getOptionIcon(option, idx)} />
|
||||
</span>
|
||||
{/if}
|
||||
{#if getOptionColour(option, idx)}
|
||||
<span class="option-extra">
|
||||
<StatusLight square color={getOptionColour(option, idx)} />
|
||||
</span>
|
||||
{/if}
|
||||
<span class="spectrum-Menu-itemLabel">
|
||||
{getOptionLabel(option, idx)}
|
||||
</span>
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||
</svg>
|
||||
</li>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
<style>
|
||||
.spectrum-Popover {
|
||||
max-height: 240px;
|
||||
z-index: 999;
|
||||
top: 100%;
|
||||
}
|
||||
.spectrum-Popover:not(.auto-width) {
|
||||
width: 100%;
|
||||
}
|
||||
.spectrum-Popover.auto-width :global(.spectrum-Menu-itemLabel) {
|
||||
max-width: 400px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.spectrum-Picker {
|
||||
width: 100%;
|
||||
box-shadow: none;
|
||||
|
@ -229,9 +228,6 @@
|
|||
.spectrum-Picker-label.auto-width.is-placeholder {
|
||||
padding-right: 2px;
|
||||
}
|
||||
.auto-width .spectrum-Menu-item {
|
||||
padding-right: var(--spacing-xl);
|
||||
}
|
||||
|
||||
/* Icon and colour alignment */
|
||||
.spectrum-Menu-checkmark {
|
||||
|
@ -241,27 +237,48 @@
|
|||
.option-extra {
|
||||
padding-right: 8px;
|
||||
}
|
||||
.option-extra.icon {
|
||||
margin: 0 -1px;
|
||||
}
|
||||
|
||||
.spectrum-Popover :global(.spectrum-Search) {
|
||||
/* Popover */
|
||||
.popover-content {
|
||||
display: contents;
|
||||
}
|
||||
.popover-content.auto-width .spectrum-Menu-itemLabel {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.popover-content:not(.auto-width) .spectrum-Menu-itemLabel {
|
||||
width: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.popover-content.auto-width .spectrum-Menu-item {
|
||||
padding-right: var(--spacing-xl);
|
||||
}
|
||||
.spectrum-Menu-item.is-disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Search styles inside popover */
|
||||
.popover-content :global(.spectrum-Search) {
|
||||
margin-top: -1px;
|
||||
margin-left: -1px;
|
||||
width: calc(100% + 2px);
|
||||
}
|
||||
.spectrum-Popover :global(.spectrum-Search input) {
|
||||
.popover-content :global(.spectrum-Search input) {
|
||||
height: auto;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
padding-top: var(--spectrum-global-dimension-size-100);
|
||||
padding-bottom: var(--spectrum-global-dimension-size-100);
|
||||
}
|
||||
.spectrum-Popover :global(.spectrum-Search .spectrum-ClearButton) {
|
||||
.popover-content :global(.spectrum-Search .spectrum-ClearButton) {
|
||||
right: 1px;
|
||||
top: 2px;
|
||||
}
|
||||
.spectrum-Popover :global(.spectrum-Search .spectrum-Textfield-icon) {
|
||||
.popover-content :global(.spectrum-Search .spectrum-Textfield-icon) {
|
||||
top: 9px;
|
||||
}
|
||||
.spectrum-Menu-item.is-disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -112,8 +112,4 @@
|
|||
.spectrum-Textfield {
|
||||
width: 100%;
|
||||
}
|
||||
input:disabled {
|
||||
color: var(--spectrum-global-color-gray-600) !important;
|
||||
-webkit-text-fill-color: var(--spectrum-global-color-gray-600) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
.icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 0 0 28px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 50%;
|
||||
|
@ -34,6 +35,7 @@
|
|||
.icon.size--S {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
flex: 0 0 22px;
|
||||
}
|
||||
.icon.size--S :global(.spectrum-Icon) {
|
||||
width: 16px;
|
||||
|
@ -46,6 +48,7 @@
|
|||
.icon.size--L {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
flex: 0 0 40px;
|
||||
}
|
||||
.icon.size--L :global(.spectrum-Icon) {
|
||||
width: 28px;
|
||||
|
|
|
@ -56,5 +56,6 @@
|
|||
--spectrum-semantic-positive-icon-color: #2d9d78;
|
||||
--spectrum-semantic-negative-icon-color: #e34850;
|
||||
min-width: 100px;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
label {
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
|
||||
.muted {
|
||||
|
|
|
@ -1,32 +1,95 @@
|
|||
<script>
|
||||
import { setContext } from "svelte"
|
||||
import clickOutside from "../Actions/click_outside"
|
||||
|
||||
export let wide = false
|
||||
export let maxWidth = "80ch"
|
||||
export let narrow = false
|
||||
export let noPadding = false
|
||||
|
||||
let sidePanelVisble = false
|
||||
|
||||
setContext("side-panel", {
|
||||
open: () => (sidePanelVisble = true),
|
||||
close: () => (sidePanelVisble = false),
|
||||
})
|
||||
</script>
|
||||
|
||||
<div style="--max-width: {maxWidth}" class:wide class:noPadding>
|
||||
<slot />
|
||||
<div class="page">
|
||||
<div class="main">
|
||||
<div class="content" class:wide class:noPadding class:narrow>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="side-panel"
|
||||
class:visible={sidePanelVisble}
|
||||
use:clickOutside={() => {
|
||||
sidePanelVisble = false
|
||||
}}
|
||||
>
|
||||
<slot name="side-panel" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
.page {
|
||||
position: relative;
|
||||
}
|
||||
.page,
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
flex: 1 1 auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.main {
|
||||
overflow: auto;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
max-width: var(--max-width);
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
padding: calc(var(--spacing-xl) * 2);
|
||||
min-height: calc(100% - var(--spacing-xl) * 4);
|
||||
flex: 1 1 auto;
|
||||
padding: 50px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.wide {
|
||||
.content.wide {
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
.content.narrow {
|
||||
max-width: 840px;
|
||||
}
|
||||
#side-panel {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 24px;
|
||||
background: var(--background);
|
||||
border-left: var(--border-light);
|
||||
width: 320px;
|
||||
max-width: calc(100vw - 48px - 48px);
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
transform: translateX(100%);
|
||||
transition: transform 130ms ease-out;
|
||||
height: calc(100% - 48px);
|
||||
z-index: 2;
|
||||
}
|
||||
#side-panel.visible {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.noPadding {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
@media (max-width: 640px) {
|
||||
.content {
|
||||
padding: 24px;
|
||||
max-width: calc(100vw - 48px) !important;
|
||||
width: calc(100vw - 48px) !important;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -30,9 +30,11 @@
|
|||
<Label>{subtitle}</Label>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot />
|
||||
</div>
|
||||
{#if $$slots.default}
|
||||
<div class="right">
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@ -45,6 +47,7 @@
|
|||
justify-content: space-between;
|
||||
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||
transition: background 130ms ease-out;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
.list-item:not(:first-child) {
|
||||
border-top: none;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
padding: 40px;
|
||||
background-color: var(--purple);
|
||||
color: white;
|
||||
font-family: var(--font-sans);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
<style>
|
||||
p, span {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--font-size-s);
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
{/if}
|
||||
|
||||
{#if showCancelButton}
|
||||
<Button group secondary newStyles on:click={close}>
|
||||
<Button group secondary on:click={close}>
|
||||
{cancelText}
|
||||
</Button>
|
||||
{/if}
|
||||
|
@ -151,7 +151,8 @@
|
|||
overflow: visible;
|
||||
}
|
||||
.spectrum-Dialog-heading {
|
||||
font-family: var(--font-sans);
|
||||
font-family: var(--font-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
.spectrum-Dialog-heading.noDivider {
|
||||
margin-bottom: 12px;
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
<style>
|
||||
p {
|
||||
margin: 0;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--font-size-s);
|
||||
}
|
||||
p.error {
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
import { createEventDispatcher } from "svelte"
|
||||
import positionDropdown from "../Actions/position_dropdown"
|
||||
import clickOutside from "../Actions/click_outside"
|
||||
import { fly } from "svelte/transition"
|
||||
import { getContext } from "svelte"
|
||||
import Context from "../context"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
|
@ -12,9 +15,10 @@
|
|||
export let portalTarget
|
||||
export let dataCy
|
||||
export let maxWidth
|
||||
|
||||
export let direction = "bottom"
|
||||
export let showTip = false
|
||||
export let open = false
|
||||
export let useAnchorWidth = false
|
||||
|
||||
let tipSvg =
|
||||
'<svg xmlns="http://www.w3.org/svg/2000" width="23" height="12" class="spectrum-Popover-tip" > <path class="spectrum-Popover-tip-triangle" d="M 0.7071067811865476 0 L 11.414213562373096 10.707106781186548 L 22.121320343559645 0" /> </svg>'
|
||||
|
@ -22,6 +26,7 @@
|
|||
$: tooltipClasses = showTip
|
||||
? `spectrum-Popover--withTip spectrum-Popover--${direction}`
|
||||
: ""
|
||||
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
|
||||
|
||||
export const show = () => {
|
||||
dispatch("open")
|
||||
|
@ -35,13 +40,22 @@
|
|||
|
||||
const handleOutsideClick = e => {
|
||||
if (open) {
|
||||
e.stopPropagation()
|
||||
// Stop propagation if the source is the anchor
|
||||
let node = e.target
|
||||
let fromAnchor = false
|
||||
while (!fromAnchor && node && node.parentNode) {
|
||||
fromAnchor = node === anchor
|
||||
node = node.parentNode
|
||||
}
|
||||
if (fromAnchor) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
// Hide the popover
|
||||
hide()
|
||||
}
|
||||
}
|
||||
|
||||
let open = null
|
||||
|
||||
function handleEscape(e) {
|
||||
if (open && e.key === "Escape") {
|
||||
hide()
|
||||
|
@ -50,15 +64,16 @@
|
|||
</script>
|
||||
|
||||
{#if open}
|
||||
<Portal target={portalTarget}>
|
||||
<Portal {target}>
|
||||
<div
|
||||
tabindex="0"
|
||||
use:positionDropdown={{ anchor, align, maxWidth }}
|
||||
use:positionDropdown={{ anchor, align, maxWidth, useAnchorWidth }}
|
||||
use:clickOutside={handleOutsideClick}
|
||||
on:keydown={handleEscape}
|
||||
class={"spectrum-Popover is-open " + (tooltipClasses || "")}
|
||||
role="presentation"
|
||||
data-cy={dataCy}
|
||||
transition:fly|local={{ y: -20, duration: 200 }}
|
||||
>
|
||||
{#if showTip}
|
||||
{@html tipSvg}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
font-size: var(--font-size-m);
|
||||
margin: 0 0 var(--spacing-l) 0;
|
||||
font-weight: 600;
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
|
||||
.input-group-column {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<script>
|
||||
export let value
|
||||
export let schema
|
||||
</script>
|
||||
|
||||
<div>{typeof value === "object" ? JSON.stringify(value) : value}</div>
|
||||
<div class:capitalise={schema?.capitalise}>
|
||||
{typeof value === "object" ? JSON.stringify(value) : value}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
|
@ -10,5 +13,10 @@
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: var(--max-cell-width);
|
||||
width: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
div.capitalise {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
* template: a HBS or JS binding to use as the value
|
||||
* background: the background color
|
||||
* color: the text color
|
||||
* borderLeft: show a left border
|
||||
* borderRight: show a right border
|
||||
*/
|
||||
export let data = []
|
||||
export let schema = {}
|
||||
|
@ -31,6 +33,7 @@
|
|||
export let allowSelectRows
|
||||
export let allowEditRows = true
|
||||
export let allowEditColumns = true
|
||||
export let allowClickRows = true
|
||||
export let selectedRows = []
|
||||
export let customRenderers = []
|
||||
export let disableSorting = false
|
||||
|
@ -270,6 +273,17 @@
|
|||
if (schema[field].align === "Right") {
|
||||
styles[field] += "justify-content: flex-end; text-align: right;"
|
||||
}
|
||||
if (schema[field].borderLeft) {
|
||||
styles[field] +=
|
||||
"border-left: 1px solid var(--spectrum-global-color-gray-200);"
|
||||
}
|
||||
if (schema[field].borderLeft) {
|
||||
styles[field] +=
|
||||
"border-right: 1px solid var(--spectrum-global-color-gray-200);"
|
||||
}
|
||||
if (schema[field].minWidth) {
|
||||
styles[field] += `min-width: ${schema[field].minWidth};`
|
||||
}
|
||||
})
|
||||
return styles
|
||||
}
|
||||
|
@ -290,7 +304,11 @@
|
|||
</slot>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="spectrum-Table" style={`${heightStyle}${gridStyle}`}>
|
||||
<div
|
||||
class="spectrum-Table"
|
||||
class:no-scroll={!rowCount}
|
||||
style={`${heightStyle}${gridStyle}`}
|
||||
>
|
||||
{#if fields.length}
|
||||
<div class="spectrum-Table-head">
|
||||
{#if showEditColumn}
|
||||
|
@ -356,7 +374,7 @@
|
|||
{/if}
|
||||
{#if sortedRows?.length}
|
||||
{#each sortedRows as row, idx}
|
||||
<div class="spectrum-Table-row">
|
||||
<div class="spectrum-Table-row" class:clickable={allowClickRows}>
|
||||
{#if showEditColumn}
|
||||
<div
|
||||
class:noBorderCheckbox={!showHeaderBorder}
|
||||
|
@ -433,10 +451,10 @@
|
|||
/* Wrapper */
|
||||
.wrapper {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
--table-bg: var(--spectrum-global-color-gray-50);
|
||||
--table-border: 1px solid var(--spectrum-alias-border-color-mid);
|
||||
--cell-padding: var(--spectrum-global-dimension-size-250);
|
||||
overflow: auto;
|
||||
}
|
||||
.wrapper--quiet {
|
||||
--table-bg: var(--spectrum-alias-background-color-transparent);
|
||||
|
@ -460,6 +478,9 @@
|
|||
display: grid;
|
||||
overflow: auto;
|
||||
}
|
||||
.spectrum-Table.no-scroll {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.spectrum-Table-head {
|
||||
|
@ -546,12 +567,13 @@
|
|||
/* Table rows */
|
||||
.spectrum-Table-row {
|
||||
display: contents;
|
||||
cursor: auto;
|
||||
}
|
||||
.spectrum-Table-row:hover .spectrum-Table-cell {
|
||||
/*background-color: var(--hover-bg) !important;*/
|
||||
.spectrum-Table-row.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.spectrum-Table-row:hover .spectrum-Table-cell:after {
|
||||
background-color: var(--spectrum-alias-highlight-hover);
|
||||
.spectrum-Table-row.clickable:hover .spectrum-Table-cell {
|
||||
background-color: var(--spectrum-global-color-gray-100);
|
||||
}
|
||||
.wrapper--quiet .spectrum-Table-row {
|
||||
border-left: none;
|
||||
|
@ -584,24 +606,13 @@
|
|||
border-bottom: 1px solid var(--spectrum-alias-border-color-mid);
|
||||
background-color: var(--table-bg);
|
||||
z-index: auto;
|
||||
transition: background-color 130ms ease-out;
|
||||
}
|
||||
.spectrum-Table-cell--edit {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
.spectrum-Table-cell:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
transition: background-color
|
||||
var(--spectrum-global-animation-duration-100, 0.13s) ease-in-out;
|
||||
}
|
||||
|
||||
/* Placeholder */
|
||||
.placeholder {
|
||||
|
|
|
@ -82,7 +82,8 @@
|
|||
.spectrum-Tabs-item {
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
.spectrum-Tabs-item.is-selected {
|
||||
.spectrum-Tabs-item.is-selected,
|
||||
.spectrum-Tabs-item:hover {
|
||||
color: var(--spectrum-global-color-gray-900);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
<style>
|
||||
.spectrum-Tags-item {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,3 +5,13 @@
|
|||
<div class="spectrum-Tags" role="list" aria-label="list">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spectrum-Tags {
|
||||
margin-top: -8px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
.spectrum-Tags :global(.spectrum-Tags-item) {
|
||||
margin: 8px 0 0 4px !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,3 +15,9 @@
|
|||
>
|
||||
<slot />
|
||||
</h1>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
font-family: var(--font-accent);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -40,12 +40,14 @@
|
|||
--rounded-medium: 8px;
|
||||
--rounded-large: 16px;
|
||||
|
||||
--font-sans: Source Sans Pro, -apple-system, BlinkMacSystemFont, Segoe UI, "Inter",
|
||||
"Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji",
|
||||
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--font-sans: "Source Sans Pro", -apple-system, BlinkMacSystemFont, Segoe UI, "Inter",
|
||||
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
--font-accent: "Source Sans Pro", -apple-system, BlinkMacSystemFont, Segoe UI, "Inter",
|
||||
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
--font-serif: "Georgia", Cambria, Times New Roman, Times, serif;
|
||||
--font-mono: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
|
||||
monospace;
|
||||
--spectrum-alias-body-text-font-family: var(--font-sans);
|
||||
|
||||
font-size: 16px;
|
||||
--font-size-xs: 0.75rem;
|
||||
|
@ -89,6 +91,8 @@
|
|||
--border-light-2: 2px var(--grey-3) solid;
|
||||
--border-blue: 2px var(--blue) solid;
|
||||
--border-transparent: 2px transparent solid;
|
||||
|
||||
--spectrum-alias-text-color-disabled: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue