1
0
Fork 0
mirror of synced 2024-10-03 10:36:59 +13:00

Basic moving around of assets.

This commit is contained in:
mike12345567 2023-03-30 16:07:59 +01:00
parent d6f38bc0ba
commit 47897c8afa
39 changed files with 1799 additions and 850 deletions

View file

@ -60,6 +60,7 @@
"@swc/core": "^1.3.25",
"@swc/jest": "^0.2.24",
"@trendyol/jest-testcontainers": "^2.1.1",
"@jest/test-sequencer": "29.5.0",
"@types/chance": "1.1.3",
"@types/ioredis": "4.28.0",
"@types/jest": "28.1.1",
@ -76,13 +77,13 @@
"@types/uuid": "8.3.4",
"chance": "1.1.8",
"ioredis-mock": "5.8.0",
"jest": "28.1.1",
"jest": "29.5.0",
"jest-serial-runner": "^1.2.1",
"koa": "2.13.4",
"nodemon": "2.0.16",
"pouchdb-adapter-memory": "7.2.2",
"timekeeper": "2.2.0",
"ts-jest": "28.0.4",
"ts-jest": "29.0.5",
"ts-node": "10.8.1",
"tsconfig-paths": "4.0.0",
"typescript": "4.7.3"

View file

@ -1,4 +1,5 @@
import { structures, testEnv } from "../../../tests"
import { structures } from "../../../tests/core"
import { testEnv } from "../../../tests/extra"
import * as auth from "../auth"
import * as events from "../../events"

View file

@ -0,0 +1,102 @@
import {
APP_PREFIX,
DocumentType,
InternalTable,
SEPARATOR,
} from "../../constants"
import { newid } from "../../newid"
/**
* Generates a new app ID.
* @returns {string} The new app ID which the app doc can be stored under.
*/
export const generateAppID = (tenantId?: string | null) => {
let id = APP_PREFIX
if (tenantId) {
id += `${tenantId}${SEPARATOR}`
}
return `${id}${newid()}`
}
/**
* Gets a new row ID for the specified table.
* @param {string} tableId The table which the row is being created for.
* @param {string|null} id If an ID is to be used then the UUID can be substituted for this.
* @returns {string} The new ID which a row doc can be stored under.
*/
export function generateRowID(tableId: string, id?: string) {
id = id || newid()
return `${DocumentType.ROW}${SEPARATOR}${tableId}${SEPARATOR}${id}`
}
/**
* Generates a new workspace ID.
* @returns {string} The new workspace ID which the workspace doc can be stored under.
*/
export function generateWorkspaceID() {
return `${DocumentType.WORKSPACE}${SEPARATOR}${newid()}`
}
/**
* Generates a new global user ID.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateGlobalUserID(id?: any) {
return `${DocumentType.USER}${SEPARATOR}${id || newid()}`
}
/**
* Generates a new user ID based on the passed in global ID.
* @param {string} globalId The ID of the global user.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateUserMetadataID(globalId: string) {
return generateRowID(InternalTable.USER_METADATA, globalId)
}
/**
* Breaks up the ID to get the global ID.
*/
export function getGlobalIDFromUserMetadataID(id: string) {
const prefix = `${DocumentType.ROW}${SEPARATOR}${InternalTable.USER_METADATA}${SEPARATOR}`
if (!id || !id.includes(prefix)) {
return id
}
return id.split(prefix)[1]
}
/**
* Generates a template ID.
* @param ownerId The owner/user of the template, this could be global or a workspace level.
*/
export function generateTemplateID(ownerId: any) {
return `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}`
}
export function generateAppUserID(prodAppId: string, userId: string) {
return `${prodAppId}${SEPARATOR}${userId}`
}
/**
* Generates a new role ID.
* @returns {string} The new role ID which the role doc can be stored under.
*/
export function generateRoleID(id?: any) {
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
}
/**
* Generates a new dev info document ID - this is scoped to a user.
* @returns {string} The new dev info ID which info for dev (like api key) can be stored under.
*/
export const generateDevInfoID = (userId: any) => {
return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}`
}
/**
* Generates a new plugin ID - to be used in the global DB.
* @returns {string} The new plugin ID which a plugin metadata document can be stored under.
*/
export const generatePluginID = (name: string) => {
return `${DocumentType.PLUGIN}${SEPARATOR}${name}`
}

View file

@ -0,0 +1,2 @@
export * from "./ids"
export * from "./params"

View file

@ -0,0 +1,176 @@
import {
DocumentType,
InternalTable,
SEPARATOR,
UNICODE_MAX,
ViewName,
} from "../../constants"
import { getProdAppID } from "../conversions"
/**
* If creating DB allDocs/query params with only a single top level ID this can be used, this
* is usually the case as most of our docs are top level e.g. tables, automations, users and so on.
* More complex cases such as link docs and rows which have multiple levels of IDs that their
* ID consists of need their own functions to build the allDocs parameters.
* @param {string} docType The type of document which input params are being built for, e.g. user,
* link, app, table and so on.
* @param {string|null} docId The ID of the document minus its type - this is only needed if looking
* for a singular document.
* @param {object} otherProps Add any other properties onto the request, e.g. include_docs.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getDocParams(
docType: string,
docId?: string | null,
otherProps: any = {}
) {
if (docId == null) {
docId = ""
}
return {
...otherProps,
startkey: `${docType}${SEPARATOR}${docId}`,
endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`,
}
}
/**
* Gets the DB allDocs/query params for retrieving a row.
* @param {string|null} tableId The table in which the rows have been stored.
* @param {string|null} rowId The ID of the row which is being specifically queried for. This can be
* left null to get all the rows in the table.
* @param {object} otherProps Any other properties to add to the request.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getRowParams(
tableId?: string | null,
rowId?: string | null,
otherProps = {}
) {
if (tableId == null) {
return getDocParams(DocumentType.ROW, null, otherProps)
}
const endOfKey = rowId == null ? `${tableId}${SEPARATOR}` : rowId
return getDocParams(DocumentType.ROW, endOfKey, otherProps)
}
/**
* Retrieve the correct index for a view based on default design DB.
*/
export function getQueryIndex(viewName: ViewName) {
return `database/${viewName}`
}
/**
* Check if a given ID is that of a table.
* @returns {boolean}
*/
export const isTableId = (id: string) => {
// this includes datasource plus tables
return (
id &&
(id.startsWith(`${DocumentType.TABLE}${SEPARATOR}`) ||
id.startsWith(`${DocumentType.DATASOURCE_PLUS}${SEPARATOR}`))
)
}
/**
* Check if a given ID is that of a datasource or datasource plus.
* @returns {boolean}
*/
export const isDatasourceId = (id: string) => {
// this covers both datasources and datasource plus
return id && id.startsWith(`${DocumentType.DATASOURCE}${SEPARATOR}`)
}
/**
* Gets parameters for retrieving workspaces.
*/
export function getWorkspaceParams(id = "", otherProps = {}) {
return {
...otherProps,
startkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}`,
endkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving users.
*/
export function getGlobalUserParams(globalId: any, otherProps: any = {}) {
if (!globalId) {
globalId = ""
}
const startkey = otherProps?.startkey
return {
...otherProps,
// need to include this incase pagination
startkey: startkey
? startkey
: `${DocumentType.USER}${SEPARATOR}${globalId}`,
endkey: `${DocumentType.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
*/
export function getUserMetadataParams(userId?: string | null, otherProps = {}) {
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
}
export function getUsersByAppParams(appId: any, otherProps: any = {}) {
const prodAppId = getProdAppID(appId)
return {
...otherProps,
startkey: prodAppId,
endkey: `${prodAppId}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a workspace level.
*/
export function getTemplateParams(
ownerId: any,
templateId: any,
otherProps = {}
) {
if (!templateId) {
templateId = ""
}
let final
if (templateId) {
final = templateId
} else {
final = `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}`
}
return {
...otherProps,
startkey: final,
endkey: `${final}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving a role, this is a utility function for the getDocParams function.
*/
export function getRoleParams(roleId?: string | null, otherProps = {}) {
return getDocParams(DocumentType.ROLE, roleId, otherProps)
}
export function getStartEndKeyURL(baseKey: any, tenantId?: string) {
const tenancy = tenantId ? `${SEPARATOR}${tenantId}` : ""
return `startkey="${baseKey}${tenancy}"&endkey="${baseKey}${tenancy}${UNICODE_MAX}"`
}
/**
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
*/
export const getPluginParams = (pluginId?: string | null, otherProps = {}) => {
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
}

View file

@ -1,257 +1,16 @@
import { newid } from "../newid"
import env from "../environment"
import {
DEFAULT_TENANT_ID,
SEPARATOR,
DocumentType,
UNICODE_MAX,
ViewName,
InternalTable,
APP_PREFIX,
} from "../constants"
import { getTenantId, getGlobalDBName } from "../context"
import { doWithDB, directCouchAllDbs } from "./db"
import { getAppMetadata } from "../cache/appMetadata"
import { isDevApp, isDevAppID, getProdAppID } from "./conversions"
import { App, Database } from "@budibase/types"
/**
* Generates a new app ID.
* @returns {string} The new app ID which the app doc can be stored under.
*/
export const generateAppID = (tenantId?: string | null) => {
let id = APP_PREFIX
if (tenantId) {
id += `${tenantId}${SEPARATOR}`
}
return `${id}${newid()}`
}
/**
* If creating DB allDocs/query params with only a single top level ID this can be used, this
* is usually the case as most of our docs are top level e.g. tables, automations, users and so on.
* More complex cases such as link docs and rows which have multiple levels of IDs that their
* ID consists of need their own functions to build the allDocs parameters.
* @param {string} docType The type of document which input params are being built for, e.g. user,
* link, app, table and so on.
* @param {string|null} docId The ID of the document minus its type - this is only needed if looking
* for a singular document.
* @param {object} otherProps Add any other properties onto the request, e.g. include_docs.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getDocParams(
docType: string,
docId?: string | null,
otherProps: any = {}
) {
if (docId == null) {
docId = ""
}
return {
...otherProps,
startkey: `${docType}${SEPARATOR}${docId}`,
endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`,
}
}
/**
* Gets the DB allDocs/query params for retrieving a row.
* @param {string|null} tableId The table in which the rows have been stored.
* @param {string|null} rowId The ID of the row which is being specifically queried for. This can be
* left null to get all the rows in the table.
* @param {object} otherProps Any other properties to add to the request.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getRowParams(
tableId?: string | null,
rowId?: string | null,
otherProps = {}
) {
if (tableId == null) {
return getDocParams(DocumentType.ROW, null, otherProps)
}
const endOfKey = rowId == null ? `${tableId}${SEPARATOR}` : rowId
return getDocParams(DocumentType.ROW, endOfKey, otherProps)
}
/**
* Retrieve the correct index for a view based on default design DB.
*/
export function getQueryIndex(viewName: ViewName) {
return `database/${viewName}`
}
/**
* Gets a new row ID for the specified table.
* @param {string} tableId The table which the row is being created for.
* @param {string|null} id If an ID is to be used then the UUID can be substituted for this.
* @returns {string} The new ID which a row doc can be stored under.
*/
export function generateRowID(tableId: string, id?: string) {
id = id || newid()
return `${DocumentType.ROW}${SEPARATOR}${tableId}${SEPARATOR}${id}`
}
/**
* Check if a given ID is that of a table.
* @returns {boolean}
*/
export const isTableId = (id: string) => {
// this includes datasource plus tables
return (
id &&
(id.startsWith(`${DocumentType.TABLE}${SEPARATOR}`) ||
id.startsWith(`${DocumentType.DATASOURCE_PLUS}${SEPARATOR}`))
)
}
/**
* Check if a given ID is that of a datasource or datasource plus.
* @returns {boolean}
*/
export const isDatasourceId = (id: string) => {
// this covers both datasources and datasource plus
return id && id.startsWith(`${DocumentType.DATASOURCE}${SEPARATOR}`)
}
/**
* Generates a new workspace ID.
* @returns {string} The new workspace ID which the workspace doc can be stored under.
*/
export function generateWorkspaceID() {
return `${DocumentType.WORKSPACE}${SEPARATOR}${newid()}`
}
/**
* Gets parameters for retrieving workspaces.
*/
export function getWorkspaceParams(id = "", otherProps = {}) {
return {
...otherProps,
startkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}`,
endkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}${UNICODE_MAX}`,
}
}
/**
* Generates a new global user ID.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateGlobalUserID(id?: any) {
return `${DocumentType.USER}${SEPARATOR}${id || newid()}`
}
/**
* Gets parameters for retrieving users.
*/
export function getGlobalUserParams(globalId: any, otherProps: any = {}) {
if (!globalId) {
globalId = ""
}
const startkey = otherProps?.startkey
return {
...otherProps,
// need to include this incase pagination
startkey: startkey
? startkey
: `${DocumentType.USER}${SEPARATOR}${globalId}`,
endkey: `${DocumentType.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
*/
export function getUserMetadataParams(userId?: string | null, otherProps = {}) {
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
}
/**
* Generates a new user ID based on the passed in global ID.
* @param {string} globalId The ID of the global user.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateUserMetadataID(globalId: string) {
return generateRowID(InternalTable.USER_METADATA, globalId)
}
/**
* Breaks up the ID to get the global ID.
*/
export function getGlobalIDFromUserMetadataID(id: string) {
const prefix = `${DocumentType.ROW}${SEPARATOR}${InternalTable.USER_METADATA}${SEPARATOR}`
if (!id || !id.includes(prefix)) {
return id
}
return id.split(prefix)[1]
}
export function getUsersByAppParams(appId: any, otherProps: any = {}) {
const prodAppId = getProdAppID(appId)
return {
...otherProps,
startkey: prodAppId,
endkey: `${prodAppId}${UNICODE_MAX}`,
}
}
/**
* Generates a template ID.
* @param ownerId The owner/user of the template, this could be global or a workspace level.
*/
export function generateTemplateID(ownerId: any) {
return `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}`
}
export function generateAppUserID(prodAppId: string, userId: string) {
return `${prodAppId}${SEPARATOR}${userId}`
}
/**
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a workspace level.
*/
export function getTemplateParams(
ownerId: any,
templateId: any,
otherProps = {}
) {
if (!templateId) {
templateId = ""
}
let final
if (templateId) {
final = templateId
} else {
final = `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}`
}
return {
...otherProps,
startkey: final,
endkey: `${final}${UNICODE_MAX}`,
}
}
/**
* Generates a new role ID.
* @returns {string} The new role ID which the role doc can be stored under.
*/
export function generateRoleID(id?: any) {
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
}
/**
* Gets parameters for retrieving a role, this is a utility function for the getDocParams function.
*/
export function getRoleParams(roleId?: string | null, otherProps = {}) {
return getDocParams(DocumentType.ROLE, roleId, otherProps)
}
export function getStartEndKeyURL(baseKey: any, tenantId?: string) {
const tenancy = tenantId ? `${SEPARATOR}${tenantId}` : ""
return `startkey="${baseKey}${tenancy}"&endkey="${baseKey}${tenancy}${UNICODE_MAX}"`
}
import { getStartEndKeyURL } from "./documents"
export * from "./documents"
/**
* if in production this will use the CouchDB _all_dbs call to retrieve a list of databases. If testing
@ -411,29 +170,6 @@ export async function dbExists(dbName: any) {
)
}
/**
* Generates a new dev info document ID - this is scoped to a user.
* @returns {string} The new dev info ID which info for dev (like api key) can be stored under.
*/
export const generateDevInfoID = (userId: any) => {
return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}`
}
/**
* Generates a new plugin ID - to be used in the global DB.
* @returns {string} The new plugin ID which a plugin metadata document can be stored under.
*/
export const generatePluginID = (name: string) => {
return `${DocumentType.PLUGIN}${SEPARATOR}${name}`
}
/**
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
*/
export const getPluginParams = (pluginId?: string | null, otherProps = {}) => {
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
}
export function pagination(
data: any[],
pageSize: number,

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`migrations should match snapshot 1`] = `
Object {
{
"_id": "migrations",
"_rev": "1-2f64479842a0513aa8b97f356b0b9127",
"createdAt": "2020-01-01T00:00:00.000Z",

View file

@ -1,28 +1,11 @@
import {
DEFAULT_TENANT_ID,
getTenantId,
getTenantIDFromAppID,
isMultiTenant,
} from "../../src/context"
import env from "../../src/environment"
import {
BBContext,
TenantResolutionStrategy,
GetTenantIdOptions,
} from "@budibase/types"
import { Header } from "../../src/constants"
import {
addTenantToUrl,
isUserInAppTenant,
getTenantIDFromCtx,
} from "../../src/tenancy"
// mock the `getTenantId` and `isMultiTenant` functions
jest.mock("../../src/context", () => ({
jest.mock("../../context", () => ({
getTenantId: jest.fn(() => "budibase"),
isMultiTenant: jest.fn(() => true),
}))
import { addTenantToUrl } from "../"
describe("addTenantToUrl", () => {
it("should append tenantId parameter to the URL", () => {
const url = "https://budibase.com"
@ -37,12 +20,6 @@ describe("addTenantToUrl", () => {
})
it("should not append tenantId parameter to the URL if isMultiTenant is false", () => {
// mock the `isMultiTenant` function to return false
jest.mock("../../src/context", () => ({
getTenantId: jest.fn(() => "default"),
isMultiTenant: jest.fn(() => false),
}))
const url = "https://budibase.com"
const expectedUrl = "https://budibase.com"
expect(addTenantToUrl(url)).toEqual(expectedUrl)

View file

@ -1,9 +1,6 @@
export * as mocks from "./mocks"
export * as structures from "./structures"
export { generator } from "./structures"
export * as testEnv from "./testEnv"
export * as testContainerUtils from "./testContainerUtils"
export * from "./jestUtils"
export { default as DBTestConfiguration } from "./DBTestConfiguration"

View file

@ -0,0 +1 @@
jest.mock("../../../src/events")

View file

@ -1,5 +1,5 @@
import { generator, uuid } from "."
import * as db from "../../../src/db/utils"
import { generateGlobalUserID } from "../../../src/db/documents"
import {
Account,
AccountSSOProvider,
@ -39,7 +39,7 @@ export const cloudAccount = (): CloudAccount => {
return {
...account(),
hosting: Hosting.CLOUD,
budibaseUserId: db.generateGlobalUserID(),
budibaseUserId: generateGlobalUserID(),
}
}

View file

@ -0,0 +1,2 @@
export * as testEnv from "./testEnv"
export * as DBTestConfiguration from "./DBTestConfiguration"

View file

@ -1,6 +1,6 @@
import env from "../../src/environment"
import * as context from "../../src/context"
import * as structures from "./structures"
import * as structures from "../core"
// TENANCY

View file

@ -1,122 +0,0 @@
import * as processors from "../../../src/events/processors"
import * as events from "../../../src/events"
jest.spyOn(processors.analyticsProcessor, "processEvent")
jest.spyOn(events.identification, "identifyTenantGroup")
jest.spyOn(events.identification, "identifyUser")
jest.spyOn(events.backfill, "appSucceeded")
jest.spyOn(events.backfill, "tenantSucceeded")
jest.spyOn(events.account, "created")
jest.spyOn(events.account, "deleted")
jest.spyOn(events.account, "verified")
jest.spyOn(events.app, "created")
jest.spyOn(events.app, "updated")
jest.spyOn(events.app, "deleted")
jest.spyOn(events.app, "published")
jest.spyOn(events.app, "unpublished")
jest.spyOn(events.app, "templateImported")
jest.spyOn(events.app, "fileImported")
jest.spyOn(events.app, "versionUpdated")
jest.spyOn(events.app, "versionReverted")
jest.spyOn(events.app, "reverted")
jest.spyOn(events.app, "exported")
jest.spyOn(events.auth, "login")
jest.spyOn(events.auth, "logout")
jest.spyOn(events.auth, "SSOCreated")
jest.spyOn(events.auth, "SSOUpdated")
jest.spyOn(events.auth, "SSOActivated")
jest.spyOn(events.auth, "SSODeactivated")
jest.spyOn(events.automation, "created")
jest.spyOn(events.automation, "deleted")
jest.spyOn(events.automation, "tested")
jest.spyOn(events.automation, "stepCreated")
jest.spyOn(events.automation, "stepDeleted")
jest.spyOn(events.automation, "triggerUpdated")
jest.spyOn(events.datasource, "created")
jest.spyOn(events.datasource, "updated")
jest.spyOn(events.datasource, "deleted")
jest.spyOn(events.email, "SMTPCreated")
jest.spyOn(events.email, "SMTPUpdated")
jest.spyOn(events.layout, "created")
jest.spyOn(events.layout, "deleted")
jest.spyOn(events.org, "nameUpdated")
jest.spyOn(events.org, "logoUpdated")
jest.spyOn(events.org, "platformURLUpdated")
jest.spyOn(events.org, "analyticsOptOut")
jest.spyOn(events.installation, "versionChecked")
jest.spyOn(events.query, "created")
jest.spyOn(events.query, "updated")
jest.spyOn(events.query, "deleted")
jest.spyOn(events.query, "imported")
jest.spyOn(events.query, "previewed")
jest.spyOn(events.role, "created")
jest.spyOn(events.role, "updated")
jest.spyOn(events.role, "deleted")
jest.spyOn(events.role, "assigned")
jest.spyOn(events.role, "unassigned")
jest.spyOn(events.rows, "imported")
jest.spyOn(events.rows, "created")
jest.spyOn(events.screen, "created")
jest.spyOn(events.screen, "deleted")
jest.spyOn(events.user, "created")
jest.spyOn(events.user, "updated")
jest.spyOn(events.user, "deleted")
jest.spyOn(events.user, "permissionAdminAssigned")
jest.spyOn(events.user, "permissionAdminRemoved")
jest.spyOn(events.user, "permissionBuilderAssigned")
jest.spyOn(events.user, "permissionBuilderRemoved")
jest.spyOn(events.user, "invited")
jest.spyOn(events.user, "inviteAccepted")
jest.spyOn(events.user, "passwordForceReset")
jest.spyOn(events.user, "passwordUpdated")
jest.spyOn(events.user, "passwordResetRequested")
jest.spyOn(events.user, "passwordReset")
jest.spyOn(events.group, "created")
jest.spyOn(events.group, "updated")
jest.spyOn(events.group, "deleted")
jest.spyOn(events.group, "usersAdded")
jest.spyOn(events.group, "usersDeleted")
jest.spyOn(events.group, "createdOnboarding")
jest.spyOn(events.group, "permissionsEdited")
jest.spyOn(events.serve, "servedBuilder")
jest.spyOn(events.serve, "servedApp")
jest.spyOn(events.serve, "servedAppPreview")
jest.spyOn(events.table, "created")
jest.spyOn(events.table, "updated")
jest.spyOn(events.table, "deleted")
jest.spyOn(events.table, "exported")
jest.spyOn(events.table, "imported")
jest.spyOn(events.view, "created")
jest.spyOn(events.view, "updated")
jest.spyOn(events.view, "deleted")
jest.spyOn(events.view, "exported")
jest.spyOn(events.view, "filterCreated")
jest.spyOn(events.view, "filterUpdated")
jest.spyOn(events.view, "filterDeleted")
jest.spyOn(events.view, "calculationCreated")
jest.spyOn(events.view, "calculationUpdated")
jest.spyOn(events.view, "calculationDeleted")
jest.spyOn(events.plugin, "init")
jest.spyOn(events.plugin, "imported")
jest.spyOn(events.plugin, "deleted")

File diff suppressed because it is too large Load diff