Merge branch 'feature/plugin-management-ui' of github.com:Budibase/budibase into feature/plugin-management-ui
This commit is contained in:
commit
cdb2452487
|
@ -0,0 +1,31 @@
|
||||||
|
<script>
|
||||||
|
import { goto } from "@roxi/routify"
|
||||||
|
import { Body, ModalContent, notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
|
import { plugins } from "stores/portal"
|
||||||
|
|
||||||
|
export let removePlugin
|
||||||
|
|
||||||
|
async function deletePlugin() {
|
||||||
|
try {
|
||||||
|
await plugins.deletePlugin(removePlugin._id, removePlugin._rev)
|
||||||
|
notifications.success(`Plugin ${removePlugin?.name} deleted.`)
|
||||||
|
$goto("./")
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error deleting plugin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ModalContent
|
||||||
|
warning
|
||||||
|
onConfirm={deletePlugin}
|
||||||
|
title="Delete Plugin"
|
||||||
|
confirmText="Delete plugin"
|
||||||
|
cancelText="Cancel"
|
||||||
|
showCloseIcon={false}
|
||||||
|
>
|
||||||
|
<Body>
|
||||||
|
Are you sure you want to delete <strong>{removePlugin?.name}</strong>
|
||||||
|
</Body>
|
||||||
|
</ModalContent>
|
|
@ -117,9 +117,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opacity {
|
|
||||||
opacity: 50%;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.desktop {
|
.desktop {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|
|
@ -13,9 +13,12 @@
|
||||||
import { plugins } from "stores/portal"
|
import { plugins } from "stores/portal"
|
||||||
import PluginRow from "./_components/PluginRow.svelte"
|
import PluginRow from "./_components/PluginRow.svelte"
|
||||||
import AddPluginModal from "./_components/AddPluginModal.svelte"
|
import AddPluginModal from "./_components/AddPluginModal.svelte"
|
||||||
|
import DeletePluginModal from "./_components/DeletePluginModal.svelte"
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
let deleteModal
|
||||||
let searchTerm = ""
|
let searchTerm = ""
|
||||||
|
let removePlugin
|
||||||
|
|
||||||
let filterOptions = [
|
let filterOptions = [
|
||||||
{ label: "All Plugins", value: "all" },
|
{ label: "All Plugins", value: "all" },
|
||||||
|
@ -31,6 +34,12 @@
|
||||||
.filter(plugin =>
|
.filter(plugin =>
|
||||||
plugin?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
plugin?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const deletePlugin = plugin => {
|
||||||
|
deleteModal.show()
|
||||||
|
removePlugin = plugin
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await plugins.load()
|
await plugins.load()
|
||||||
})
|
})
|
||||||
|
@ -66,7 +75,7 @@
|
||||||
|
|
||||||
{#if $plugins}
|
{#if $plugins}
|
||||||
{#each filteredPlugins as plugin}
|
{#each filteredPlugins as plugin}
|
||||||
<PluginRow {plugin} />
|
<PluginRow {plugin} {deletePlugin} />
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -75,6 +84,9 @@
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<AddPluginModal />
|
<AddPluginModal />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal bind:this={deleteModal}>
|
||||||
|
<DeletePluginModal {removePlugin} />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.filters {
|
.filters {
|
||||||
|
|
|
@ -32,10 +32,12 @@ export function createPluginsStore() {
|
||||||
case "npm":
|
case "npm":
|
||||||
pluginData.npmToken = auth
|
pluginData.npmToken = auth
|
||||||
break
|
break
|
||||||
|
case "github":
|
||||||
|
pluginData.githubToken = auth
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = await API.createPlugin(pluginData)
|
let res = await API.createPlugin(pluginData)
|
||||||
console.log("RESP", res)
|
|
||||||
|
|
||||||
let newPlugin = res.plugins[0]
|
let newPlugin = res.plugins[0]
|
||||||
update(state => {
|
update(state => {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
extractPluginTarball,
|
extractPluginTarball,
|
||||||
createNpmPlugin,
|
createNpmPlugin,
|
||||||
createUrlPlugin,
|
createUrlPlugin,
|
||||||
|
createGithubPlugin,
|
||||||
} from "../../utilities/fileSystem"
|
} from "../../utilities/fileSystem"
|
||||||
import { getGlobalDB } from "@budibase/backend-core/tenancy"
|
import { getGlobalDB } from "@budibase/backend-core/tenancy"
|
||||||
import { generatePluginID, getPluginParams } from "../../db/utils"
|
import { generatePluginID, getPluginParams } from "../../db/utils"
|
||||||
|
@ -61,7 +62,10 @@ export async function create(ctx: any) {
|
||||||
directory = directoryNpm
|
directory = directoryNpm
|
||||||
break
|
break
|
||||||
case "github":
|
case "github":
|
||||||
console.log("github")
|
const { metadata: metadataGithub, directory: directoryGithub } =
|
||||||
|
await createGithubPlugin(ctx, url, name, githubToken)
|
||||||
|
metadata = metadataGithub
|
||||||
|
directory = directoryGithub
|
||||||
break
|
break
|
||||||
case "url":
|
case "url":
|
||||||
const { metadata: metadataUrl, directory: directoryUrl } =
|
const { metadata: metadataUrl, directory: directoryUrl } =
|
||||||
|
|
|
@ -31,6 +31,7 @@ const MemoryStream = require("memorystream")
|
||||||
const { getAppId } = require("@budibase/backend-core/context")
|
const { getAppId } = require("@budibase/backend-core/context")
|
||||||
const tar = require("tar")
|
const tar = require("tar")
|
||||||
const fetch = require("node-fetch")
|
const fetch = require("node-fetch")
|
||||||
|
const { NodeVM } = require("vm2")
|
||||||
|
|
||||||
const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
||||||
const NODE_MODULES_PATH = join(TOP_LEVEL_PATH, "node_modules")
|
const NODE_MODULES_PATH = join(TOP_LEVEL_PATH, "node_modules")
|
||||||
|
@ -378,8 +379,69 @@ exports.createUrlPlugin = async (url, name = "", headers = {}) => {
|
||||||
return await downloadUnzipPlugin(name, url, headers)
|
return await downloadUnzipPlugin(name, url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.createGithubPlugin = async (ctx, url, name = "", token = "") => {
|
||||||
|
let githubRepositoryUrl
|
||||||
|
let githubUrl
|
||||||
|
|
||||||
|
if (url.includes(".git")) {
|
||||||
|
githubRepositoryUrl = token
|
||||||
|
? url.replace("https://", `https://${token}@`)
|
||||||
|
: url
|
||||||
|
githubUrl = url.replace(".git", "")
|
||||||
|
} else {
|
||||||
|
githubRepositoryUrl = token
|
||||||
|
? `${url}.git`.replace("https://", `https://${token}@`)
|
||||||
|
: `${url}.git`
|
||||||
|
githubUrl = url
|
||||||
|
}
|
||||||
|
|
||||||
|
const githubApiUrl = githubUrl.replace(
|
||||||
|
"https://github.com/",
|
||||||
|
"https://api.github.com/repos/"
|
||||||
|
)
|
||||||
|
const headers = token ? { Authorization: `Bearer ${token}` } : {}
|
||||||
|
try {
|
||||||
|
const pluginRaw = await fetch(githubApiUrl, { headers })
|
||||||
|
if (pluginRaw.status !== 200) {
|
||||||
|
throw `Repository not found`
|
||||||
|
}
|
||||||
|
|
||||||
|
let pluginDetails = await pluginRaw.json()
|
||||||
|
const pluginName = pluginDetails.name || name
|
||||||
|
|
||||||
|
const path = join(budibaseTempDir(), pluginName)
|
||||||
|
// Remove first if exists
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
fs.rmSync(path, { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
fs.mkdirSync(path)
|
||||||
|
|
||||||
|
const script = `
|
||||||
|
module.exports = async () => {
|
||||||
|
const child_process = require('child_process')
|
||||||
|
child_process.execSync(\`git clone ${githubRepositoryUrl} ${join(
|
||||||
|
budibaseTempDir(),
|
||||||
|
pluginName
|
||||||
|
)}\`);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const scriptRunner = new NodeVM({
|
||||||
|
require: {
|
||||||
|
external: true,
|
||||||
|
builtin: ["child_process"],
|
||||||
|
root: "./",
|
||||||
|
},
|
||||||
|
}).run(script)
|
||||||
|
|
||||||
|
await scriptRunner()
|
||||||
|
|
||||||
|
return await getPluginMetadata(path)
|
||||||
|
} catch (e) {
|
||||||
|
throw e.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const downloadUnzipPlugin = async (name, url, headers = {}) => {
|
const downloadUnzipPlugin = async (name, url, headers = {}) => {
|
||||||
console.log(name, url, headers)
|
|
||||||
const path = join(budibaseTempDir(), name)
|
const path = join(budibaseTempDir(), name)
|
||||||
try {
|
try {
|
||||||
// Remove first if exists
|
// Remove first if exists
|
||||||
|
@ -407,7 +469,6 @@ const downloadUnzipPlugin = async (name, url, headers = {}) => {
|
||||||
exports.downloadUnzipPlugin = downloadUnzipPlugin
|
exports.downloadUnzipPlugin = downloadUnzipPlugin
|
||||||
|
|
||||||
const getPluginMetadata = async path => {
|
const getPluginMetadata = async path => {
|
||||||
console.log(path)
|
|
||||||
let metadata = {}
|
let metadata = {}
|
||||||
try {
|
try {
|
||||||
const pkg = fs.readFileSync(join(path, "package.json"), "utf8")
|
const pkg = fs.readFileSync(join(path, "package.json"), "utf8")
|
||||||
|
|
Loading…
Reference in New Issue