Merge pull request #7774 from Budibase/events/plugins
Plugin init, imported and deleted events
This commit is contained in:
commit
b8462eea0c
15 changed files with 138 additions and 18 deletions
|
@ -5,8 +5,15 @@ import {
|
||||||
DatasourceCreatedEvent,
|
DatasourceCreatedEvent,
|
||||||
DatasourceUpdatedEvent,
|
DatasourceUpdatedEvent,
|
||||||
DatasourceDeletedEvent,
|
DatasourceDeletedEvent,
|
||||||
|
SourceName,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
|
||||||
|
function isCustom(datasource: Datasource) {
|
||||||
|
const sources = Object.values(SourceName)
|
||||||
|
// if not in the base source list, then it must be custom
|
||||||
|
return !sources.includes(datasource.source)
|
||||||
|
}
|
||||||
|
|
||||||
export async function created(
|
export async function created(
|
||||||
datasource: Datasource,
|
datasource: Datasource,
|
||||||
timestamp?: string | number
|
timestamp?: string | number
|
||||||
|
@ -14,6 +21,7 @@ export async function created(
|
||||||
const properties: DatasourceCreatedEvent = {
|
const properties: DatasourceCreatedEvent = {
|
||||||
datasourceId: datasource._id as string,
|
datasourceId: datasource._id as string,
|
||||||
source: datasource.source,
|
source: datasource.source,
|
||||||
|
custom: isCustom(datasource),
|
||||||
}
|
}
|
||||||
await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp)
|
await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +30,7 @@ export async function updated(datasource: Datasource) {
|
||||||
const properties: DatasourceUpdatedEvent = {
|
const properties: DatasourceUpdatedEvent = {
|
||||||
datasourceId: datasource._id as string,
|
datasourceId: datasource._id as string,
|
||||||
source: datasource.source,
|
source: datasource.source,
|
||||||
|
custom: isCustom(datasource),
|
||||||
}
|
}
|
||||||
await publishEvent(Event.DATASOURCE_UPDATED, properties)
|
await publishEvent(Event.DATASOURCE_UPDATED, properties)
|
||||||
}
|
}
|
||||||
|
@ -30,6 +39,7 @@ export async function deleted(datasource: Datasource) {
|
||||||
const properties: DatasourceDeletedEvent = {
|
const properties: DatasourceDeletedEvent = {
|
||||||
datasourceId: datasource._id as string,
|
datasourceId: datasource._id as string,
|
||||||
source: datasource.source,
|
source: datasource.source,
|
||||||
|
custom: isCustom(datasource),
|
||||||
}
|
}
|
||||||
await publishEvent(Event.DATASOURCE_DELETED, properties)
|
await publishEvent(Event.DATASOURCE_DELETED, properties)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,3 +18,4 @@ export * as view from "./view"
|
||||||
export * as installation from "./installation"
|
export * as installation from "./installation"
|
||||||
export * as backfill from "./backfill"
|
export * as backfill from "./backfill"
|
||||||
export * as group from "./group"
|
export * as group from "./group"
|
||||||
|
export * as plugin from "./plugin"
|
||||||
|
|
41
packages/backend-core/src/events/publishers/plugin.ts
Normal file
41
packages/backend-core/src/events/publishers/plugin.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { publishEvent } from "../events"
|
||||||
|
import {
|
||||||
|
Event,
|
||||||
|
Plugin,
|
||||||
|
PluginDeletedEvent,
|
||||||
|
PluginImportedEvent,
|
||||||
|
PluginInitEvent,
|
||||||
|
} from "@budibase/types"
|
||||||
|
|
||||||
|
export async function init(plugin: Plugin) {
|
||||||
|
const properties: PluginInitEvent = {
|
||||||
|
type: plugin.schema.type,
|
||||||
|
name: plugin.name,
|
||||||
|
description: plugin.description,
|
||||||
|
version: plugin.version,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.PLUGIN_INIT, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function imported(plugin: Plugin) {
|
||||||
|
const properties: PluginImportedEvent = {
|
||||||
|
pluginId: plugin._id as string,
|
||||||
|
type: plugin.schema.type,
|
||||||
|
source: plugin.source,
|
||||||
|
name: plugin.name,
|
||||||
|
description: plugin.description,
|
||||||
|
version: plugin.version,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.PLUGIN_IMPORTED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleted(plugin: Plugin) {
|
||||||
|
const properties: PluginDeletedEvent = {
|
||||||
|
pluginId: plugin._id as string,
|
||||||
|
type: plugin.schema.type,
|
||||||
|
name: plugin.name,
|
||||||
|
description: plugin.description,
|
||||||
|
version: plugin.version,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.PLUGIN_DELETED, properties)
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
const { Event } = require("@budibase/types")
|
||||||
|
|
||||||
exports.CommandWords = {
|
exports.CommandWords = {
|
||||||
BACKUPS: "backups",
|
BACKUPS: "backups",
|
||||||
HOSTING: "hosting",
|
HOSTING: "hosting",
|
||||||
|
@ -15,6 +17,7 @@ exports.AnalyticsEvents = {
|
||||||
OptOut: "analytics:opt:out",
|
OptOut: "analytics:opt:out",
|
||||||
OptIn: "analytics:opt:in",
|
OptIn: "analytics:opt:in",
|
||||||
SelfHostInit: "hosting:init",
|
SelfHostInit: "hosting:init",
|
||||||
|
PluginInit: Event.PLUGIN_INIT,
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS"
|
exports.POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS"
|
||||||
|
|
11
packages/cli/src/events.js
Normal file
11
packages/cli/src/events.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
const AnalyticsClient = require("./analytics/Client")
|
||||||
|
|
||||||
|
const client = new AnalyticsClient()
|
||||||
|
|
||||||
|
exports.captureEvent = (event, properties) => {
|
||||||
|
client.capture({
|
||||||
|
distinctId: "cli",
|
||||||
|
event,
|
||||||
|
properties,
|
||||||
|
})
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ const fs = require("fs")
|
||||||
const compose = require("docker-compose")
|
const compose = require("docker-compose")
|
||||||
const makeEnv = require("./makeEnv")
|
const makeEnv = require("./makeEnv")
|
||||||
const axios = require("axios")
|
const axios = require("axios")
|
||||||
const AnalyticsClient = require("../analytics/Client")
|
const { captureEvent } = require("../events")
|
||||||
|
|
||||||
const BUDIBASE_SERVICES = ["app-service", "worker-service", "proxy-service"]
|
const BUDIBASE_SERVICES = ["app-service", "worker-service", "proxy-service"]
|
||||||
const ERROR_FILE = "docker-error.log"
|
const ERROR_FILE = "docker-error.log"
|
||||||
|
@ -22,8 +22,6 @@ const FILE_URLS = [
|
||||||
]
|
]
|
||||||
const DO_USER_DATA_URL = "http://169.254.169.254/metadata/v1/user-data"
|
const DO_USER_DATA_URL = "http://169.254.169.254/metadata/v1/user-data"
|
||||||
|
|
||||||
const client = new AnalyticsClient()
|
|
||||||
|
|
||||||
async function downloadFiles() {
|
async function downloadFiles() {
|
||||||
const promises = []
|
const promises = []
|
||||||
for (let url of FILE_URLS) {
|
for (let url of FILE_URLS) {
|
||||||
|
@ -72,12 +70,8 @@ async function init(type) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.capture({
|
captureEvent(AnalyticsEvents.SelfHostInit, {
|
||||||
distinctId: "cli",
|
type,
|
||||||
event: AnalyticsEvents.SelfHostInit,
|
|
||||||
properties: {
|
|
||||||
type,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
await downloadFiles()
|
await downloadFiles()
|
||||||
const config = isQuick ? makeEnv.QUICK_CONFIG : {}
|
const config = isQuick ? makeEnv.QUICK_CONFIG : {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const Command = require("../structures/Command")
|
const Command = require("../structures/Command")
|
||||||
const { CommandWords } = require("../constants")
|
const { CommandWords, AnalyticsEvents } = require("../constants")
|
||||||
const { getSkeleton, fleshOutSkeleton } = require("./skeleton")
|
const { getSkeleton, fleshOutSkeleton } = require("./skeleton")
|
||||||
const questions = require("../questions")
|
const questions = require("../questions")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
|
@ -8,6 +8,7 @@ const { validate } = require("@budibase/backend-core/plugins")
|
||||||
const { runPkgCommand } = require("../exec")
|
const { runPkgCommand } = require("../exec")
|
||||||
const { join } = require("path")
|
const { join } = require("path")
|
||||||
const { success, error, info, moveDirectory } = require("../utils")
|
const { success, error, info, moveDirectory } = require("../utils")
|
||||||
|
const { captureEvent } = require("../events")
|
||||||
|
|
||||||
function checkInPlugin() {
|
function checkInPlugin() {
|
||||||
if (!fs.existsSync("package.json")) {
|
if (!fs.existsSync("package.json")) {
|
||||||
|
@ -58,7 +59,7 @@ async function init(opts) {
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const desc = await questions.string(
|
const description = await questions.string(
|
||||||
"Description",
|
"Description",
|
||||||
`An amazing Budibase ${type}!`
|
`An amazing Budibase ${type}!`
|
||||||
)
|
)
|
||||||
|
@ -67,7 +68,7 @@ async function init(opts) {
|
||||||
// get the skeleton
|
// get the skeleton
|
||||||
console.log(info("Retrieving project..."))
|
console.log(info("Retrieving project..."))
|
||||||
await getSkeleton(type, name)
|
await getSkeleton(type, name)
|
||||||
await fleshOutSkeleton(type, name, desc, version)
|
await fleshOutSkeleton(type, name, description, version)
|
||||||
console.log(info("Installing dependencies..."))
|
console.log(info("Installing dependencies..."))
|
||||||
await runPkgCommand("install", join(process.cwd(), name))
|
await runPkgCommand("install", join(process.cwd(), name))
|
||||||
// if no parent directory desired move to cwd
|
// if no parent directory desired move to cwd
|
||||||
|
@ -77,6 +78,12 @@ async function init(opts) {
|
||||||
} else {
|
} else {
|
||||||
console.log(info(`Plugin created in directory "${name}"`))
|
console.log(info(`Plugin created in directory "${name}"`))
|
||||||
}
|
}
|
||||||
|
captureEvent(AnalyticsEvents.PluginInit, {
|
||||||
|
type,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verify() {
|
async function verify() {
|
||||||
|
|
|
@ -8,9 +8,10 @@ import {
|
||||||
uploadDirectory,
|
uploadDirectory,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
} from "@budibase/backend-core/objectStore"
|
} from "@budibase/backend-core/objectStore"
|
||||||
import { PluginType, FileType, PluginSource } from "@budibase/types"
|
import { PluginType, FileType, PluginSource, Plugin } from "@budibase/types"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { ClientAppSocket } from "../../../websocket"
|
import { ClientAppSocket } from "../../../websocket"
|
||||||
|
import { events } from "@budibase/backend-core"
|
||||||
|
|
||||||
export async function getPlugins(type?: PluginType) {
|
export async function getPlugins(type?: PluginType) {
|
||||||
const db = getGlobalDB()
|
const db = getGlobalDB()
|
||||||
|
@ -113,11 +114,12 @@ export async function destroy(ctx: any) {
|
||||||
const { pluginId } = ctx.params
|
const { pluginId } = ctx.params
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const plugin = await db.get(pluginId)
|
const plugin: Plugin = await db.get(pluginId)
|
||||||
const bucketPath = `${plugin.name}/`
|
const bucketPath = `${plugin.name}/`
|
||||||
await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath)
|
await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath)
|
||||||
|
|
||||||
await db.remove(pluginId, plugin._rev)
|
await db.remove(pluginId, plugin._rev)
|
||||||
|
await events.plugin.deleted(plugin)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const errMsg = err?.message ? err?.message : err
|
const errMsg = err?.message ? err?.message : err
|
||||||
|
|
||||||
|
@ -131,7 +133,7 @@ export async function destroy(ctx: any) {
|
||||||
export async function storePlugin(
|
export async function storePlugin(
|
||||||
metadata: any,
|
metadata: any,
|
||||||
directory: any,
|
directory: any,
|
||||||
source?: string
|
source?: PluginSource
|
||||||
) {
|
) {
|
||||||
const db = getGlobalDB()
|
const db = getGlobalDB()
|
||||||
const version = metadata.package.version,
|
const version = metadata.package.version,
|
||||||
|
@ -173,7 +175,7 @@ export async function storePlugin(
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
rev = undefined
|
rev = undefined
|
||||||
}
|
}
|
||||||
let doc = {
|
let doc: Plugin = {
|
||||||
_id: pluginId,
|
_id: pluginId,
|
||||||
_rev: rev,
|
_rev: rev,
|
||||||
...metadata,
|
...metadata,
|
||||||
|
@ -192,6 +194,7 @@ export async function storePlugin(
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.put(doc)
|
const response = await db.put(doc)
|
||||||
|
await events.plugin.imported(doc)
|
||||||
ClientAppSocket.emit("plugin-update", { name, hash })
|
ClientAppSocket.emit("plugin-update", { name, hash })
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
|
@ -199,7 +202,7 @@ export async function storePlugin(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function processPlugin(plugin: FileType, source?: string) {
|
export async function processPlugin(plugin: FileType, source?: PluginSource) {
|
||||||
const { metadata, directory } = await fileUpload(plugin)
|
const { metadata, directory } = await fileUpload(plugin)
|
||||||
validate(metadata?.schema)
|
validate(metadata?.schema)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from "./config"
|
export * from "./config"
|
||||||
export * from "./user"
|
export * from "./user"
|
||||||
export * from "./userGroup"
|
export * from "./userGroup"
|
||||||
|
export * from "./plugin"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Document } from "../document"
|
||||||
|
|
||||||
export enum PluginType {
|
export enum PluginType {
|
||||||
DATASOURCE = "datasource",
|
DATASOURCE = "datasource",
|
||||||
COMPONENT = "component",
|
COMPONENT = "component",
|
||||||
|
@ -14,4 +16,17 @@ export interface FileType {
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Plugin extends Document {
|
||||||
|
description: string
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
jsUrl?: string
|
||||||
|
source: PluginSource
|
||||||
|
package: { [key: string]: any }
|
||||||
|
schema: {
|
||||||
|
type: PluginType
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const PLUGIN_TYPE_ARR = Object.values(PluginType)
|
export const PLUGIN_TYPE_ARR = Object.values(PluginType)
|
|
@ -1,7 +1,6 @@
|
||||||
export * from "./account"
|
export * from "./account"
|
||||||
export * from "./app"
|
export * from "./app"
|
||||||
export * from "./global"
|
export * from "./global"
|
||||||
export * from "./plugin"
|
|
||||||
export * from "./platform"
|
export * from "./platform"
|
||||||
export * from "./document"
|
export * from "./document"
|
||||||
export * from "./pouch"
|
export * from "./pouch"
|
||||||
|
|
|
@ -3,14 +3,17 @@ import { BaseEvent } from "./event"
|
||||||
export interface DatasourceCreatedEvent extends BaseEvent {
|
export interface DatasourceCreatedEvent extends BaseEvent {
|
||||||
datasourceId: string
|
datasourceId: string
|
||||||
source: string
|
source: string
|
||||||
|
custom: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DatasourceUpdatedEvent extends BaseEvent {
|
export interface DatasourceUpdatedEvent extends BaseEvent {
|
||||||
datasourceId: string
|
datasourceId: string
|
||||||
source: string
|
source: string
|
||||||
|
custom: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DatasourceDeletedEvent extends BaseEvent {
|
export interface DatasourceDeletedEvent extends BaseEvent {
|
||||||
datasourceId: string
|
datasourceId: string
|
||||||
source: string
|
source: string
|
||||||
|
custom: boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,11 @@ export enum Event {
|
||||||
USER_GROUP_USERS_REMOVED = "user_group:users_deleted",
|
USER_GROUP_USERS_REMOVED = "user_group:users_deleted",
|
||||||
USER_GROUP_PERMISSIONS_EDITED = "user_group:permissions_edited",
|
USER_GROUP_PERMISSIONS_EDITED = "user_group:permissions_edited",
|
||||||
USER_GROUP_ONBOARDING = "user_group:onboarding_added",
|
USER_GROUP_ONBOARDING = "user_group:onboarding_added",
|
||||||
|
|
||||||
|
// PLUGIN
|
||||||
|
PLUGIN_INIT = "plugin:init",
|
||||||
|
PLUGIN_IMPORTED = "plugin:imported",
|
||||||
|
PLUGIN_DELETED = "plugin:deleted",
|
||||||
}
|
}
|
||||||
|
|
||||||
// properties added at the final stage of the event pipeline
|
// properties added at the final stage of the event pipeline
|
||||||
|
|
|
@ -19,3 +19,4 @@ export * from "./account"
|
||||||
export * from "./backfill"
|
export * from "./backfill"
|
||||||
export * from "./identification"
|
export * from "./identification"
|
||||||
export * from "./userGroup"
|
export * from "./userGroup"
|
||||||
|
export * from "./plugin"
|
||||||
|
|
26
packages/types/src/sdk/events/plugin.ts
Normal file
26
packages/types/src/sdk/events/plugin.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { BaseEvent } from "./event"
|
||||||
|
import { PluginSource, PluginType } from "../../"
|
||||||
|
|
||||||
|
export interface PluginInitEvent extends BaseEvent {
|
||||||
|
type: PluginType
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PluginImportedEvent extends BaseEvent {
|
||||||
|
pluginId: string
|
||||||
|
type: PluginType
|
||||||
|
source: PluginSource
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PluginDeletedEvent extends BaseEvent {
|
||||||
|
pluginId: string
|
||||||
|
type: PluginType
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
description: string
|
||||||
|
}
|
Loading…
Reference in a new issue