Altering object store so that all writes/reads to the object store have the dev app prefix replaced with standard app.
This commit is contained in:
commit
f4e3e1d196
|
@ -1,6 +1,9 @@
|
||||||
const { newid } = require("../hashing")
|
const { newid } = require("../hashing")
|
||||||
const Replication = require("./Replication")
|
const Replication = require("./Replication")
|
||||||
|
|
||||||
|
const UNICODE_MAX = "\ufff0"
|
||||||
|
const SEPARATOR = "_"
|
||||||
|
|
||||||
exports.ViewNames = {
|
exports.ViewNames = {
|
||||||
USER_BY_EMAIL: "by_email",
|
USER_BY_EMAIL: "by_email",
|
||||||
}
|
}
|
||||||
|
@ -13,17 +16,16 @@ exports.StaticDatabases = {
|
||||||
|
|
||||||
const DocumentTypes = {
|
const DocumentTypes = {
|
||||||
USER: "us",
|
USER: "us",
|
||||||
APP: "app",
|
|
||||||
GROUP: "group",
|
GROUP: "group",
|
||||||
CONFIG: "config",
|
CONFIG: "config",
|
||||||
TEMPLATE: "template",
|
TEMPLATE: "template",
|
||||||
|
APP: "app",
|
||||||
|
APP_DEV: "app_dev",
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.DocumentTypes = DocumentTypes
|
exports.DocumentTypes = DocumentTypes
|
||||||
|
exports.APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
||||||
const UNICODE_MAX = "\ufff0"
|
exports.APP_DEV_PREFIX = DocumentTypes.APP_DEV + SEPARATOR
|
||||||
const SEPARATOR = "_"
|
|
||||||
|
|
||||||
exports.SEPARATOR = SEPARATOR
|
exports.SEPARATOR = SEPARATOR
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,6 +10,7 @@ const fs = require("fs")
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
const { budibaseTempDir, ObjectStoreBuckets } = require("./utils")
|
const { budibaseTempDir, ObjectStoreBuckets } = require("./utils")
|
||||||
const { v4 } = require("uuid")
|
const { v4 } = require("uuid")
|
||||||
|
const { APP_PREFIX, APP_DEV_PREFIX } = require("../db/utils")
|
||||||
|
|
||||||
const streamPipeline = promisify(stream.pipeline)
|
const streamPipeline = promisify(stream.pipeline)
|
||||||
// use this as a temporary store of buckets that are being created
|
// use this as a temporary store of buckets that are being created
|
||||||
|
@ -28,6 +29,16 @@ const STRING_CONTENT_TYPES = [
|
||||||
CONTENT_TYPE_MAP.js,
|
CONTENT_TYPE_MAP.js,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// does normal sanitization and then swaps dev apps to apps
|
||||||
|
function sanitizeKey(input) {
|
||||||
|
return sanitize(sanitizeBucket(input)).replace(/\\/g, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// simply handles the dev app to app conversion
|
||||||
|
function sanitizeBucket(input) {
|
||||||
|
return input.replace(new RegExp(APP_DEV_PREFIX, "g"), APP_PREFIX)
|
||||||
|
}
|
||||||
|
|
||||||
function publicPolicy(bucketName) {
|
function publicPolicy(bucketName) {
|
||||||
return {
|
return {
|
||||||
Version: "2012-10-17",
|
Version: "2012-10-17",
|
||||||
|
@ -61,7 +72,7 @@ exports.ObjectStore = bucket => {
|
||||||
s3ForcePathStyle: true,
|
s3ForcePathStyle: true,
|
||||||
signatureVersion: "v4",
|
signatureVersion: "v4",
|
||||||
params: {
|
params: {
|
||||||
Bucket: bucket,
|
Bucket: sanitizeBucket(bucket),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if (env.MINIO_URL) {
|
if (env.MINIO_URL) {
|
||||||
|
@ -75,6 +86,7 @@ exports.ObjectStore = bucket => {
|
||||||
* if it does not exist then it will create it.
|
* if it does not exist then it will create it.
|
||||||
*/
|
*/
|
||||||
exports.makeSureBucketExists = async (client, bucketName) => {
|
exports.makeSureBucketExists = async (client, bucketName) => {
|
||||||
|
bucketName = sanitizeBucket(bucketName)
|
||||||
try {
|
try {
|
||||||
await client
|
await client
|
||||||
.headBucket({
|
.headBucket({
|
||||||
|
@ -114,16 +126,16 @@ exports.makeSureBucketExists = async (client, bucketName) => {
|
||||||
* Uploads the contents of a file given the required parameters, useful when
|
* Uploads the contents of a file given the required parameters, useful when
|
||||||
* temp files in use (for example file uploaded as an attachment).
|
* temp files in use (for example file uploaded as an attachment).
|
||||||
*/
|
*/
|
||||||
exports.upload = async ({ bucket, filename, path, type, metadata }) => {
|
exports.upload = async ({ bucket: bucketName, filename, path, type, metadata }) => {
|
||||||
const extension = [...filename.split(".")].pop()
|
const extension = [...filename.split(".")].pop()
|
||||||
const fileBytes = fs.readFileSync(path)
|
const fileBytes = fs.readFileSync(path)
|
||||||
|
|
||||||
const objectStore = exports.ObjectStore(bucket)
|
const objectStore = exports.ObjectStore(bucketName)
|
||||||
await exports.makeSureBucketExists(objectStore, bucket)
|
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
// windows file paths need to be converted to forward slashes for s3
|
// windows file paths need to be converted to forward slashes for s3
|
||||||
Key: sanitize(filename).replace(/\\/g, "/"),
|
Key: sanitizeKey(filename),
|
||||||
Body: fileBytes,
|
Body: fileBytes,
|
||||||
ContentType: type || CONTENT_TYPE_MAP[extension.toLowerCase()],
|
ContentType: type || CONTENT_TYPE_MAP[extension.toLowerCase()],
|
||||||
}
|
}
|
||||||
|
@ -137,13 +149,13 @@ exports.upload = async ({ bucket, filename, path, type, metadata }) => {
|
||||||
* Similar to the upload function but can be used to send a file stream
|
* Similar to the upload function but can be used to send a file stream
|
||||||
* through to the object store.
|
* through to the object store.
|
||||||
*/
|
*/
|
||||||
exports.streamUpload = async (bucket, filename, stream) => {
|
exports.streamUpload = async (bucketName, filename, stream) => {
|
||||||
const objectStore = exports.ObjectStore(bucket)
|
const objectStore = exports.ObjectStore(bucketName)
|
||||||
await exports.makeSureBucketExists(objectStore, bucket)
|
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
Bucket: bucket,
|
Bucket: sanitizeBucket(bucketName),
|
||||||
Key: sanitize(filename).replace(/\\/g, "/"),
|
Key: sanitizeKey(filename),
|
||||||
Body: stream,
|
Body: stream,
|
||||||
}
|
}
|
||||||
return objectStore.upload(params).promise()
|
return objectStore.upload(params).promise()
|
||||||
|
@ -153,11 +165,11 @@ exports.streamUpload = async (bucket, filename, stream) => {
|
||||||
* retrieves the contents of a file from the object store, if it is a known content type it
|
* retrieves the contents of a file from the object store, if it is a known content type it
|
||||||
* will be converted, otherwise it will be returned as a buffer stream.
|
* will be converted, otherwise it will be returned as a buffer stream.
|
||||||
*/
|
*/
|
||||||
exports.retrieve = async (bucket, filepath) => {
|
exports.retrieve = async (bucketName, filepath) => {
|
||||||
const objectStore = exports.ObjectStore(bucket)
|
const objectStore = exports.ObjectStore(bucketName)
|
||||||
const params = {
|
const params = {
|
||||||
Bucket: bucket,
|
Bucket: sanitizeBucket(bucketName),
|
||||||
Key: sanitize(filepath).replace(/\\/g, "/"),
|
Key: sanitizeKey(filepath),
|
||||||
}
|
}
|
||||||
const response = await objectStore.getObject(params).promise()
|
const response = await objectStore.getObject(params).promise()
|
||||||
// currently these are all strings
|
// currently these are all strings
|
||||||
|
@ -171,17 +183,21 @@ exports.retrieve = async (bucket, filepath) => {
|
||||||
/**
|
/**
|
||||||
* Same as retrieval function but puts to a temporary file.
|
* Same as retrieval function but puts to a temporary file.
|
||||||
*/
|
*/
|
||||||
exports.retrieveToTmp = async (bucket, filepath) => {
|
exports.retrieveToTmp = async (bucketName, filepath) => {
|
||||||
const data = await exports.retrieve(bucket, filepath)
|
bucketName = sanitizeBucket(bucketName)
|
||||||
|
filepath = sanitizeKey(filepath)
|
||||||
|
const data = await exports.retrieve(bucketName, filepath)
|
||||||
const outputPath = join(budibaseTempDir(), v4())
|
const outputPath = join(budibaseTempDir(), v4())
|
||||||
fs.writeFileSync(outputPath, data)
|
fs.writeFileSync(outputPath, data)
|
||||||
return outputPath
|
return outputPath
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.deleteFolder = async (bucket, folder) => {
|
exports.deleteFolder = async (bucketName, folder) => {
|
||||||
const client = exports.ObjectStore(bucket)
|
bucketName = sanitizeBucket(bucketName)
|
||||||
|
folder = sanitizeKey(folder)
|
||||||
|
const client = exports.ObjectStore(bucketName)
|
||||||
const listParams = {
|
const listParams = {
|
||||||
Bucket: bucket,
|
Bucket: bucketName,
|
||||||
Prefix: folder,
|
Prefix: folder,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +206,7 @@ exports.deleteFolder = async (bucket, folder) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const deleteParams = {
|
const deleteParams = {
|
||||||
Bucket: bucket,
|
Bucket: bucketName,
|
||||||
Delete: {
|
Delete: {
|
||||||
Objects: [],
|
Objects: [],
|
||||||
},
|
},
|
||||||
|
@ -203,28 +219,31 @@ exports.deleteFolder = async (bucket, folder) => {
|
||||||
response = await client.deleteObjects(deleteParams).promise()
|
response = await client.deleteObjects(deleteParams).promise()
|
||||||
// can only empty 1000 items at once
|
// can only empty 1000 items at once
|
||||||
if (response.Deleted.length === 1000) {
|
if (response.Deleted.length === 1000) {
|
||||||
return exports.deleteFolder(bucket, folder)
|
return exports.deleteFolder(bucketName, folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.uploadDirectory = async (bucket, localPath, bucketPath) => {
|
exports.uploadDirectory = async (bucketName, localPath, bucketPath) => {
|
||||||
|
bucketName = sanitizeBucket(bucketName)
|
||||||
let uploads = []
|
let uploads = []
|
||||||
const files = fs.readdirSync(localPath, { withFileTypes: true })
|
const files = fs.readdirSync(localPath, { withFileTypes: true })
|
||||||
for (let file of files) {
|
for (let file of files) {
|
||||||
const path = join(bucketPath, file.name)
|
const path = sanitizeKey(join(bucketPath, file.name))
|
||||||
const local = join(localPath, file.name)
|
const local = join(localPath, file.name)
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
uploads.push(exports.uploadDirectory(bucket, local, path))
|
uploads.push(exports.uploadDirectory(bucketName, local, path))
|
||||||
} else {
|
} else {
|
||||||
uploads.push(
|
uploads.push(
|
||||||
exports.streamUpload(bucket, path, fs.createReadStream(local))
|
exports.streamUpload(bucketName, path, fs.createReadStream(local))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Promise.all(uploads)
|
await Promise.all(uploads)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.downloadTarball = async (url, bucket, path) => {
|
exports.downloadTarball = async (url, bucketName, path) => {
|
||||||
|
bucketName = sanitizeBucket(bucketName)
|
||||||
|
path = sanitizeKey(path)
|
||||||
const response = await fetch(url)
|
const response = await fetch(url)
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`unexpected response ${response.statusText}`)
|
throw new Error(`unexpected response ${response.statusText}`)
|
||||||
|
@ -233,7 +252,7 @@ exports.downloadTarball = async (url, bucket, path) => {
|
||||||
const tmpPath = join(budibaseTempDir(), path)
|
const tmpPath = join(budibaseTempDir(), path)
|
||||||
await streamPipeline(response.body, zlib.Unzip(), tar.extract(tmpPath))
|
await streamPipeline(response.body, zlib.Unzip(), tar.extract(tmpPath))
|
||||||
if (!env.isTest()) {
|
if (!env.isTest()) {
|
||||||
await exports.uploadDirectory(bucket, tmpPath, path)
|
await exports.uploadDirectory(bucketName, tmpPath, path)
|
||||||
}
|
}
|
||||||
// return the temporary path incase there is a use for it
|
// return the temporary path incase there is a use for it
|
||||||
return tmpPath
|
return tmpPath
|
||||||
|
|
|
@ -9,20 +9,29 @@
|
||||||
Link,
|
Link,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { gradient } from "actions"
|
import { gradient } from "actions"
|
||||||
|
import { AppStatus } from "constants"
|
||||||
import { url } from "@roxi/routify"
|
import { url } from "@roxi/routify"
|
||||||
|
|
||||||
export let app
|
export let app
|
||||||
export let exportApp
|
export let exportApp
|
||||||
export let deleteApp
|
export let deleteApp
|
||||||
|
export let appStatus
|
||||||
|
|
||||||
|
let href =
|
||||||
|
appStatus === AppStatus.DEV ? $url(`../../app/${app._id}`) : `/${app._id}`
|
||||||
|
let target = appStatus === AppStatus.DEV ? "_self" : "_target"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<Layout noPadding gap="XS" alignContent="start">
|
<Layout noPadding gap="XS" alignContent="start">
|
||||||
<div class="preview" use:gradient={{ seed: app.name }} />
|
<div class="preview" use:gradient={{ seed: app.name }} />
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Link href={$url(`../../app/${app._id}`)}>
|
<Link {href} {target}>
|
||||||
<Heading size="XS">
|
<Heading size="XS">
|
||||||
|
<<<<<<< HEAD
|
||||||
{app._id}
|
{app._id}
|
||||||
|
=======
|
||||||
|
>>>>>>> c3e1b1d30235b8945424cf59a41e112f92942dc6
|
||||||
{app.name}
|
{app.name}
|
||||||
</Heading>
|
</Heading>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -34,13 +43,14 @@
|
||||||
<MenuItem on:click={() => deleteApp(app)} icon="Delete">
|
<MenuItem on:click={() => deleteApp(app)} icon="Delete">
|
||||||
Delete
|
Delete
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem on:click={() => deleteApp(app)} icon="Code">Develop</MenuItem>
|
||||||
</ActionMenu>
|
</ActionMenu>
|
||||||
</div>
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<Body noPadding size="S">
|
<Body noPadding size="S">
|
||||||
Edited {Math.floor(1 + Math.random() * 10)} months ago
|
Edited {Math.floor(1 + Math.random() * 10)} months ago
|
||||||
</Body>
|
</Body>
|
||||||
{#if Math.random() > 0.5}
|
{#if appStatus === AppStatus.DEV && app.lockedBy}
|
||||||
<Icon name="LockClosed" />
|
<Icon name="LockClosed" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Link,
|
Link,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
|
import { AppStatus } from "constants"
|
||||||
import { url } from "@roxi/routify"
|
import { url } from "@roxi/routify"
|
||||||
|
|
||||||
export let app
|
export let app
|
||||||
|
@ -15,11 +16,16 @@
|
||||||
export let exportApp
|
export let exportApp
|
||||||
export let deleteApp
|
export let deleteApp
|
||||||
export let last
|
export let last
|
||||||
|
export let appStatus
|
||||||
|
|
||||||
|
let href =
|
||||||
|
appStatus === AppStatus.DEV ? $url(`../../app/${app._id}`) : `/${app._id}`
|
||||||
|
let target = appStatus === AppStatus.DEV ? "_self" : "_target"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="title" class:last>
|
<div class="title" class:last>
|
||||||
<div class="preview" use:gradient={{ seed: app.name }} />
|
<div class="preview" use:gradient={{ seed: app.name }} />
|
||||||
<Link href={$url(`../../app/${app._id}`)}>
|
<Link {href} {target}>
|
||||||
<Heading size="XS">
|
<Heading size="XS">
|
||||||
{app.name}
|
{app.name}
|
||||||
</Heading>
|
</Heading>
|
||||||
|
@ -29,15 +35,12 @@
|
||||||
Edited {Math.round(Math.random() * 10 + 1)} months ago
|
Edited {Math.round(Math.random() * 10 + 1)} months ago
|
||||||
</div>
|
</div>
|
||||||
<div class:last>
|
<div class:last>
|
||||||
{#if Math.random() < 0.33}
|
{#if app.lockedBy}
|
||||||
|
<div class="status status--locked-you" />
|
||||||
|
Locked by {app.lockedBy.email}
|
||||||
|
{:else}
|
||||||
<div class="status status--open" />
|
<div class="status status--open" />
|
||||||
Open
|
Open
|
||||||
{:else if Math.random() < 0.33}
|
|
||||||
<div class="status status--locked-other" />
|
|
||||||
Locked by Will Wheaton
|
|
||||||
{:else}
|
|
||||||
<div class="status status--locked-you" />
|
|
||||||
Locked by you
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class:last>
|
<div class:last>
|
||||||
|
|
|
@ -9,6 +9,10 @@ export const FrontendTypes = {
|
||||||
NONE: "none",
|
NONE: "none",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const AppStatus = {
|
||||||
|
DEV: "dev",
|
||||||
|
}
|
||||||
|
|
||||||
// fields on the user table that cannot be edited
|
// fields on the user table that cannot be edited
|
||||||
export const UNEDITABLE_USER_FIELDS = ["email", "password", "roleId", "status"]
|
export const UNEDITABLE_USER_FIELDS = ["email", "password", "roleId", "status"]
|
||||||
|
|
||||||
|
|
|
@ -93,12 +93,13 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
checkKeys()
|
checkKeys()
|
||||||
await apps.load()
|
await apps.load(appStatus)
|
||||||
loaded = true
|
loaded = true
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Page wide>
|
<Page wide>
|
||||||
|
<<<<<<< HEAD
|
||||||
{#if $apps.length}
|
{#if $apps.length}
|
||||||
<Layout noPadding>
|
<Layout noPadding>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
|
@ -132,7 +133,42 @@
|
||||||
icon="ViewRow"
|
icon="ViewRow"
|
||||||
/>
|
/>
|
||||||
</ActionGroup>
|
</ActionGroup>
|
||||||
|
=======
|
||||||
|
<Layout noPadding>
|
||||||
|
<div class="title">
|
||||||
|
<Heading>Apps</Heading>
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button secondary on:click={initiateAppImport}>Import app</Button>
|
||||||
|
<Button cta on:click={initiateAppCreation}>Create new app</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
|
<div class="filter">
|
||||||
|
<div class="select">
|
||||||
|
<Select
|
||||||
|
bind:value={appStatus}
|
||||||
|
options={[
|
||||||
|
{ label: "Deployed", value: "deployed" },
|
||||||
|
{ label: "In Development", value: "dev" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
>>>>>>> c3e1b1d30235b8945424cf59a41e112f92942dc6
|
||||||
</div>
|
</div>
|
||||||
|
<ActionGroup>
|
||||||
|
<ActionButton
|
||||||
|
on:click={() => (layout = "grid")}
|
||||||
|
selected={layout === "grid"}
|
||||||
|
quiet
|
||||||
|
icon="ClassicGridView"
|
||||||
|
/>
|
||||||
|
<ActionButton
|
||||||
|
on:click={() => (layout = "table")}
|
||||||
|
selected={layout === "table"}
|
||||||
|
quiet
|
||||||
|
icon="ViewRow"
|
||||||
|
/>
|
||||||
|
</ActionGroup>
|
||||||
|
</div>
|
||||||
|
{#if $apps.length}
|
||||||
<div
|
<div
|
||||||
class:appGrid={layout === "grid"}
|
class:appGrid={layout === "grid"}
|
||||||
class:appTable={layout === "table"}
|
class:appTable={layout === "table"}
|
||||||
|
@ -140,6 +176,7 @@
|
||||||
{#each $apps as app, idx (app._id)}
|
{#each $apps as app, idx (app._id)}
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={layout === "grid" ? AppCard : AppRow}
|
this={layout === "grid" ? AppCard : AppRow}
|
||||||
|
{appStatus}
|
||||||
{app}
|
{app}
|
||||||
{openApp}
|
{openApp}
|
||||||
{exportApp}
|
{exportApp}
|
||||||
|
@ -148,8 +185,8 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
{/if}
|
||||||
{/if}
|
</Layout>
|
||||||
{#if !$apps.length && !creatingApp && loaded}
|
{#if !$apps.length && !creatingApp && loaded}
|
||||||
<div class="empty-wrapper">
|
<div class="empty-wrapper">
|
||||||
<Modal inline>
|
<Modal inline>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
const newid = require("./newid")
|
const newid = require("./newid")
|
||||||
|
const {
|
||||||
|
DocumentTypes: CoreDocTypes,
|
||||||
|
APP_DEV_PREFIX,
|
||||||
|
APP_PREFIX,
|
||||||
|
SEPARATOR,
|
||||||
|
} = require("@budibase/auth").db
|
||||||
|
|
||||||
const UNICODE_MAX = "\ufff0"
|
const UNICODE_MAX = "\ufff0"
|
||||||
const SEPARATOR = "_"
|
|
||||||
|
|
||||||
const StaticDatabases = {
|
const StaticDatabases = {
|
||||||
BUILDER: {
|
BUILDER: {
|
||||||
|
@ -16,13 +21,13 @@ const AppStatus = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DocumentTypes = {
|
const DocumentTypes = {
|
||||||
|
APP: CoreDocTypes.APP,
|
||||||
|
APP_DEV: CoreDocTypes.APP_DEV,
|
||||||
TABLE: "ta",
|
TABLE: "ta",
|
||||||
ROW: "ro",
|
ROW: "ro",
|
||||||
USER: "us",
|
USER: "us",
|
||||||
AUTOMATION: "au",
|
AUTOMATION: "au",
|
||||||
LINK: "li",
|
LINK: "li",
|
||||||
APP: "app",
|
|
||||||
APP_DEV: "app_dev",
|
|
||||||
ROLE: "role",
|
ROLE: "role",
|
||||||
WEBHOOK: "wh",
|
WEBHOOK: "wh",
|
||||||
INSTANCE: "inst",
|
INSTANCE: "inst",
|
||||||
|
@ -45,8 +50,8 @@ const SearchIndexes = {
|
||||||
ROWS: "rows",
|
ROWS: "rows",
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
exports.APP_PREFIX = APP_PREFIX
|
||||||
exports.APP_DEV_PREFIX = DocumentTypes.APP_DEV + SEPARATOR
|
exports.APP_DEV_PREFIX = APP_DEV_PREFIX
|
||||||
exports.StaticDatabases = StaticDatabases
|
exports.StaticDatabases = StaticDatabases
|
||||||
exports.ViewNames = ViewNames
|
exports.ViewNames = ViewNames
|
||||||
exports.InternalTables = InternalTables
|
exports.InternalTables = InternalTables
|
||||||
|
|
Loading…
Reference in New Issue