Merge pull request #8672 from Budibase/feature/default-internal-datasource
Default Datasource and sample row data
This commit is contained in:
commit
f043b8deda
|
@ -0,0 +1,44 @@
|
||||||
|
exports.UserStatus = {
|
||||||
|
ACTIVE: "active",
|
||||||
|
INACTIVE: "inactive",
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.Cookie = {
|
||||||
|
CurrentApp: "budibase:currentapp",
|
||||||
|
Auth: "budibase:auth",
|
||||||
|
Init: "budibase:init",
|
||||||
|
ACCOUNT_RETURN_URL: "budibase:account:returnurl",
|
||||||
|
DatasourceAuth: "budibase:datasourceauth",
|
||||||
|
OIDC_CONFIG: "budibase:oidc:config",
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.Header = {
|
||||||
|
API_KEY: "x-budibase-api-key",
|
||||||
|
LICENSE_KEY: "x-budibase-license-key",
|
||||||
|
API_VER: "x-budibase-api-version",
|
||||||
|
APP_ID: "x-budibase-app-id",
|
||||||
|
TYPE: "x-budibase-type",
|
||||||
|
PREVIEW_ROLE: "x-budibase-role",
|
||||||
|
TENANT_ID: "x-budibase-tenant-id",
|
||||||
|
TOKEN: "x-budibase-token",
|
||||||
|
CSRF_TOKEN: "x-csrf-token",
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.GlobalRoles = {
|
||||||
|
OWNER: "owner",
|
||||||
|
ADMIN: "admin",
|
||||||
|
BUILDER: "builder",
|
||||||
|
WORKSPACE_MANAGER: "workspace_manager",
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.Config = {
|
||||||
|
SETTINGS: "settings",
|
||||||
|
ACCOUNT: "account",
|
||||||
|
SMTP: "smtp",
|
||||||
|
GOOGLE: "google",
|
||||||
|
OIDC: "oidc",
|
||||||
|
OIDC_LOGOS: "logos_oidc",
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.MAX_VALID_DATE = new Date(2147483647000)
|
||||||
|
exports.DEFAULT_TENANT_ID = "default"
|
|
@ -92,3 +92,4 @@ export const StaticDatabases = {
|
||||||
export const APP_PREFIX = DocumentType.APP + SEPARATOR
|
export const APP_PREFIX = DocumentType.APP + SEPARATOR
|
||||||
export const APP_DEV = DocumentType.APP_DEV + SEPARATOR
|
export const APP_DEV = DocumentType.APP_DEV + SEPARATOR
|
||||||
export const APP_DEV_PREFIX = APP_DEV
|
export const APP_DEV_PREFIX = APP_DEV
|
||||||
|
export const BUDIBASE_DATASOURCE_TYPE = "budibase"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { goto, params } from "@roxi/routify"
|
import { goto, params } from "@roxi/routify"
|
||||||
import { BUDIBASE_INTERNAL_DB } from "constants"
|
import { BUDIBASE_INTERNAL_DB_ID } from "constants/backend"
|
||||||
import { database, datasources, queries, tables, views } from "stores/backend"
|
import { database, datasources, queries, tables, views } from "stores/backend"
|
||||||
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
|
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
|
||||||
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
|
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
|
||||||
|
@ -129,7 +129,7 @@
|
||||||
size="18"
|
size="18"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#if datasource._id !== BUDIBASE_INTERNAL_DB}
|
{#if datasource._id !== BUDIBASE_INTERNAL_DB_ID}
|
||||||
<EditDatasourcePopover {datasource} />
|
<EditDatasourcePopover {datasource} />
|
||||||
{/if}
|
{/if}
|
||||||
</NavItem>
|
</NavItem>
|
||||||
|
|
|
@ -10,10 +10,23 @@
|
||||||
Divider,
|
Divider,
|
||||||
Layout,
|
Layout,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
|
import { datasources } from "stores/backend"
|
||||||
import TableDataImport from "../TableDataImport.svelte"
|
import TableDataImport from "../TableDataImport.svelte"
|
||||||
|
import {
|
||||||
|
BUDIBASE_INTERNAL_DB_ID,
|
||||||
|
BUDIBASE_DATASOURCE_TYPE,
|
||||||
|
} from "constants/backend"
|
||||||
import { buildAutoColumn, getAutoColumnInformation } from "builderStore/utils"
|
import { buildAutoColumn, getAutoColumnInformation } from "builderStore/utils"
|
||||||
|
|
||||||
$: tableNames = $tables.list.map(table => table.name)
|
$: tableNames = $tables.list.map(table => table.name)
|
||||||
|
$: selectedSource = $datasources.list.find(
|
||||||
|
source => source._id === $datasources.selected
|
||||||
|
)
|
||||||
|
|
||||||
|
$: isSelectedInternal = selectedSource?.type === BUDIBASE_DATASOURCE_TYPE
|
||||||
|
$: targetDatasourceId = isSelectedInternal
|
||||||
|
? selectedSource._id
|
||||||
|
: BUDIBASE_INTERNAL_DB_ID
|
||||||
|
|
||||||
export let name
|
export let name
|
||||||
let dataImport
|
let dataImport
|
||||||
|
@ -45,7 +58,7 @@
|
||||||
schema: addAutoColumns(name, dataImport.schema || {}),
|
schema: addAutoColumns(name, dataImport.schema || {}),
|
||||||
dataImport,
|
dataImport,
|
||||||
type: "internal",
|
type: "internal",
|
||||||
sourceId: "bb_internal",
|
sourceId: targetDatasourceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only set primary display if defined
|
// Only set primary display if defined
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
import { datasources, integrations, queries } from "stores/backend"
|
import { datasources, integrations, queries } from "stores/backend"
|
||||||
import BindingBuilder from "components/integration/QueryBindingBuilder.svelte"
|
import BindingBuilder from "components/integration/QueryBindingBuilder.svelte"
|
||||||
import IntegrationQueryEditor from "components/integration/index.svelte"
|
import IntegrationQueryEditor from "components/integration/index.svelte"
|
||||||
import { BUDIBASE_DATASOURCE_ID } from "constants/backend"
|
import {
|
||||||
|
BUDIBASE_INTERNAL_DB_ID,
|
||||||
|
BUDIBASE_DATASOURCE_TYPE,
|
||||||
|
} from "constants/backend"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
export let bindings = []
|
export let bindings = []
|
||||||
|
@ -14,7 +17,8 @@
|
||||||
)
|
)
|
||||||
// Executequery must exclude budibase datasource
|
// Executequery must exclude budibase datasource
|
||||||
$: executeQueryDatasources = $datasources.list.filter(
|
$: executeQueryDatasources = $datasources.list.filter(
|
||||||
x => x._id !== BUDIBASE_DATASOURCE_ID
|
x =>
|
||||||
|
x._id !== BUDIBASE_INTERNAL_DB_ID && x.type !== BUDIBASE_DATASOURCE_TYPE
|
||||||
)
|
)
|
||||||
|
|
||||||
function fetchQueryDefinition(query) {
|
function fetchQueryDefinition(query) {
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { writable, get as svelteGet } from "svelte/store"
|
import { writable, get as svelteGet } from "svelte/store"
|
||||||
import { notifications, Input, ModalContent, Dropzone } from "@budibase/bbui"
|
import {
|
||||||
|
notifications,
|
||||||
|
Input,
|
||||||
|
ModalContent,
|
||||||
|
Dropzone,
|
||||||
|
Toggle,
|
||||||
|
} from "@budibase/bbui"
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { apps, admin, auth } from "stores/portal"
|
import { apps, admin, auth } from "stores/portal"
|
||||||
|
@ -16,6 +22,7 @@
|
||||||
|
|
||||||
let creating = false
|
let creating = false
|
||||||
let defaultAppName
|
let defaultAppName
|
||||||
|
let includeSampleDB = true
|
||||||
|
|
||||||
const values = writable({ name: "", url: null })
|
const values = writable({ name: "", url: null })
|
||||||
const validation = createValidationStore()
|
const validation = createValidationStore()
|
||||||
|
@ -98,6 +105,8 @@
|
||||||
data.append("templateName", template.name)
|
data.append("templateName", template.name)
|
||||||
data.append("templateKey", template.key)
|
data.append("templateKey", template.key)
|
||||||
data.append("templateFile", $values.file)
|
data.append("templateFile", $values.file)
|
||||||
|
} else {
|
||||||
|
data.append("sampleData", includeSampleDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create App
|
// Create App
|
||||||
|
@ -192,6 +201,15 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
{#if !template && !template?.fromFile}
|
||||||
|
<span>
|
||||||
|
<Toggle
|
||||||
|
text="Include sample data"
|
||||||
|
bind:value={includeSampleDB}
|
||||||
|
disabled={creating}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -173,7 +173,8 @@ export const SWITCHABLE_TYPES = [
|
||||||
...ALLOWABLE_NUMBER_TYPES,
|
...ALLOWABLE_NUMBER_TYPES,
|
||||||
]
|
]
|
||||||
|
|
||||||
export const BUDIBASE_DATASOURCE_ID = "bb_internal"
|
export const BUDIBASE_INTERNAL_DB_ID = "bb_internal"
|
||||||
|
export const BUDIBASE_DATASOURCE_TYPE = "budibase"
|
||||||
|
|
||||||
export const IntegrationTypes = {
|
export const IntegrationTypes = {
|
||||||
POSTGRES: "POSTGRES",
|
POSTGRES: "POSTGRES",
|
||||||
|
|
|
@ -43,8 +43,6 @@ export const LAYOUT_NAMES = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BUDIBASE_INTERNAL_DB = "bb_internal"
|
|
||||||
|
|
||||||
// one or more word characters and whitespace
|
// one or more word characters and whitespace
|
||||||
export const APP_NAME_REGEX = /^[\w\s]+$/
|
export const APP_NAME_REGEX = /^[\w\s]+$/
|
||||||
// zero or more non-whitespace characters
|
// zero or more non-whitespace characters
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { redirect, params } from "@roxi/routify"
|
import { redirect } from "@roxi/routify"
|
||||||
import { Button, Tabs, Tab, Layout } from "@budibase/bbui"
|
import { Button, Tabs, Tab, Layout } from "@budibase/bbui"
|
||||||
import { BUDIBASE_INTERNAL_DB } from "constants"
|
|
||||||
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
|
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
|
||||||
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
|
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
|
||||||
|
|
||||||
|
@ -9,10 +8,6 @@
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
|
||||||
$: isExternal =
|
|
||||||
$params.selectedDatasource &&
|
|
||||||
$params.selectedDatasource !== BUDIBASE_INTERNAL_DB
|
|
||||||
|
|
||||||
function selectFirstDatasource() {
|
function selectFirstDatasource() {
|
||||||
$redirect("./table")
|
$redirect("./table")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
import { Button, Heading, Body, Layout, Modal, Divider } from "@budibase/bbui"
|
import { Button, Heading, Body, Layout, Modal, Divider } from "@budibase/bbui"
|
||||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||||
import ICONS from "components/backend/DatasourceNavigator/icons"
|
import ICONS from "components/backend/DatasourceNavigator/icons"
|
||||||
import { tables } from "stores/backend"
|
import { tables, datasources } from "stores/backend"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
|
||||||
|
$: internalTablesBySourceId = $tables.list.filter(
|
||||||
|
table =>
|
||||||
|
table.type !== "external" && $datasources.selected === table.sourceId
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
|
@ -27,7 +32,7 @@
|
||||||
<Divider />
|
<Divider />
|
||||||
<Heading size="S">Tables</Heading>
|
<Heading size="S">Tables</Heading>
|
||||||
<div class="table-list">
|
<div class="table-list">
|
||||||
{#each $tables.list.filter(table => table.type !== "external") as table}
|
{#each internalTablesBySourceId as table}
|
||||||
<div
|
<div
|
||||||
class="table-list-item"
|
class="table-list-item"
|
||||||
on:click={$goto(`../../table/${table._id}`)}
|
on:click={$goto(`../../table/${table._id}`)}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<script>
|
||||||
|
import { datasources } from "stores/backend"
|
||||||
|
|
||||||
|
datasources.select("datasource_internal_bb_default")
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot />
|
|
@ -0,0 +1,87 @@
|
||||||
|
<script>
|
||||||
|
import { Button, Heading, Body, Layout, Modal, Divider } from "@budibase/bbui"
|
||||||
|
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||||
|
import ICONS from "components/backend/DatasourceNavigator/icons"
|
||||||
|
import { tables, datasources } from "stores/backend"
|
||||||
|
import { goto } from "@roxi/routify"
|
||||||
|
|
||||||
|
let modal
|
||||||
|
$: internalTablesBySourceId = $tables.list.filter(
|
||||||
|
table =>
|
||||||
|
table.type !== "external" && $datasources.selected === table.sourceId
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:this={modal}>
|
||||||
|
<CreateTableModal />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<Layout>
|
||||||
|
<Layout gap="XS" noPadding>
|
||||||
|
<header>
|
||||||
|
<svelte:component this={ICONS.BUDIBASE} height="26" width="26" />
|
||||||
|
<Heading size="M">Sample Data</Heading>
|
||||||
|
</header>
|
||||||
|
<Body size="M">A little something to get you up and running!</Body>
|
||||||
|
<Body size="M"
|
||||||
|
>If you have no need for this datasource, feel free to delete it.</Body
|
||||||
|
>
|
||||||
|
</Layout>
|
||||||
|
<Divider />
|
||||||
|
<Heading size="S">Tables</Heading>
|
||||||
|
<div class="table-list">
|
||||||
|
<!-- {JSON.stringify($tables.list.map(source => source.sourceId))} -->
|
||||||
|
{#each internalTablesBySourceId as table}
|
||||||
|
<div
|
||||||
|
class="table-list-item"
|
||||||
|
on:click={$goto(`../../table/${table._id}`)}
|
||||||
|
>
|
||||||
|
<Body size="S">{table.name}</Body>
|
||||||
|
{#if table.primaryDisplay}
|
||||||
|
<Body size="S">Display column: {table.primaryDisplay}</Body>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button cta on:click={modal.show}>Create new table</Button>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 640px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-l);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-list-item {
|
||||||
|
border-radius: var(--border-radius-m);
|
||||||
|
background: var(--background);
|
||||||
|
border: var(--border-dark);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 0.75fr 20px;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--spacing-m);
|
||||||
|
gap: var(--layout-xs);
|
||||||
|
transition: 200ms background ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-list-item:hover {
|
||||||
|
background: var(--grey-1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
$: setupComplete =
|
$: setupComplete =
|
||||||
$datasources.list.find(x => (x._id = "bb_internal"))?.entities.length > 1 ||
|
$datasources.list.find(x => (x._id = "bb_internal"))?.entities?.length >
|
||||||
$datasources.list.length > 1
|
1 || $datasources.list.length > 1
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!setupComplete && !$admin.isDev) {
|
if (!setupComplete && !$admin.isDev) {
|
||||||
|
|
|
@ -25,8 +25,14 @@ import {
|
||||||
migrations,
|
migrations,
|
||||||
} from "@budibase/backend-core"
|
} from "@budibase/backend-core"
|
||||||
import { USERS_TABLE_SCHEMA } from "../../constants"
|
import { USERS_TABLE_SCHEMA } from "../../constants"
|
||||||
|
import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default"
|
||||||
|
|
||||||
import { removeAppFromUserRoles } from "../../utilities/workerRequests"
|
import { removeAppFromUserRoles } from "../../utilities/workerRequests"
|
||||||
import { clientLibraryPath, stringToReadStream } from "../../utilities"
|
import {
|
||||||
|
clientLibraryPath,
|
||||||
|
stringToReadStream,
|
||||||
|
isQsTrue,
|
||||||
|
} from "../../utilities"
|
||||||
import { getLocksById } from "../../utilities/redis"
|
import { getLocksById } from "../../utilities/redis"
|
||||||
import {
|
import {
|
||||||
updateClientLibrary,
|
updateClientLibrary,
|
||||||
|
@ -117,7 +123,7 @@ const checkAppName = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createInstance(template: any) {
|
async function createInstance(template: any, includeSampleData: boolean) {
|
||||||
const tenantId = tenancy.isMultiTenant() ? tenancy.getTenantId() : null
|
const tenantId = tenancy.isMultiTenant() ? tenancy.getTenantId() : null
|
||||||
const baseAppId = generateAppID(tenantId)
|
const baseAppId = generateAppID(tenantId)
|
||||||
const appId = generateDevAppID(baseAppId)
|
const appId = generateDevAppID(baseAppId)
|
||||||
|
@ -149,11 +155,23 @@ async function createInstance(template: any) {
|
||||||
} else {
|
} else {
|
||||||
// create the users table
|
// create the users table
|
||||||
await db.put(USERS_TABLE_SCHEMA)
|
await db.put(USERS_TABLE_SCHEMA)
|
||||||
|
|
||||||
|
if (includeSampleData) {
|
||||||
|
// create ootb stock db
|
||||||
|
await addDefaultTables(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { _id: appId }
|
return { _id: appId }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const addDefaultTables = async (db: any) => {
|
||||||
|
const defaultDbDocs = buildDefaultDocs()
|
||||||
|
|
||||||
|
// add in the default db data docs - tables, datasource, rows and links
|
||||||
|
await db.bulkDocs([...defaultDbDocs])
|
||||||
|
}
|
||||||
|
|
||||||
export const fetch = async (ctx: any) => {
|
export const fetch = async (ctx: any) => {
|
||||||
const dev = ctx.query && ctx.query.status === AppStatus.DEV
|
const dev = ctx.query && ctx.query.status === AppStatus.DEV
|
||||||
const all = ctx.query && ctx.query.status === AppStatus.ALL
|
const all = ctx.query && ctx.query.status === AppStatus.ALL
|
||||||
|
@ -234,7 +252,8 @@ const performAppCreate = async (ctx: any) => {
|
||||||
if (ctx.request.files && ctx.request.files.templateFile) {
|
if (ctx.request.files && ctx.request.files.templateFile) {
|
||||||
instanceConfig.file = ctx.request.files.templateFile
|
instanceConfig.file = ctx.request.files.templateFile
|
||||||
}
|
}
|
||||||
const instance = await createInstance(instanceConfig)
|
const includeSampleData = isQsTrue(ctx.request.body.sampleData)
|
||||||
|
const instance = await createInstance(instanceConfig, includeSampleData)
|
||||||
const appId = instance._id
|
const appId = instance._id
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,14 @@ const {
|
||||||
BudibaseInternalDB,
|
BudibaseInternalDB,
|
||||||
getTableParams,
|
getTableParams,
|
||||||
} = require("../../db/utils")
|
} = require("../../db/utils")
|
||||||
|
const { destroy: tableDestroy } = require("./table/internal")
|
||||||
const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
|
const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
|
||||||
const { getIntegration } = require("../../integrations")
|
const { getIntegration } = require("../../integrations")
|
||||||
const { getDatasourceAndQuery } = require("./row/utils")
|
const { getDatasourceAndQuery } = require("./row/utils")
|
||||||
const { invalidateDynamicVariables } = require("../../threads/utils")
|
const { invalidateDynamicVariables } = require("../../threads/utils")
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
const { getAppDB } = require("@budibase/backend-core/context")
|
||||||
const { events } = require("@budibase/backend-core")
|
const { events } = require("@budibase/backend-core")
|
||||||
|
const { db: dbCore } = require("@budibase/backend-core")
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
exports.fetch = async function (ctx) {
|
||||||
// Get internal tables
|
// Get internal tables
|
||||||
|
@ -21,11 +23,16 @@ exports.fetch = async function (ctx) {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const internal = internalTables.rows.map(row => row.doc)
|
|
||||||
|
const internal = internalTables.rows.reduce((acc, row) => {
|
||||||
|
const sourceId = row.doc.sourceId || "bb_internal"
|
||||||
|
acc[sourceId] = acc[sourceId] || []
|
||||||
|
acc[sourceId].push(row.doc)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
const bbInternalDb = {
|
const bbInternalDb = {
|
||||||
...BudibaseInternalDB,
|
...BudibaseInternalDB,
|
||||||
entities: internal,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get external datasources
|
// Get external datasources
|
||||||
|
@ -37,11 +44,17 @@ exports.fetch = async function (ctx) {
|
||||||
)
|
)
|
||||||
).rows.map(row => row.doc)
|
).rows.map(row => row.doc)
|
||||||
|
|
||||||
for (let datasource of datasources) {
|
const allDatasources = [bbInternalDb, ...datasources]
|
||||||
|
|
||||||
|
for (let datasource of allDatasources) {
|
||||||
if (datasource.config && datasource.config.auth) {
|
if (datasource.config && datasource.config.auth) {
|
||||||
// strip secrets from response so they don't show in the network request
|
// strip secrets from response so they don't show in the network request
|
||||||
delete datasource.config.auth
|
delete datasource.config.auth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (datasource.type === dbCore.BUDIBASE_DATASOURCE_TYPE) {
|
||||||
|
datasource.entities = internal[datasource._id]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = [bbInternalDb, ...datasources]
|
ctx.body = [bbInternalDb, ...datasources]
|
||||||
|
@ -196,12 +209,44 @@ exports.save = async function (ctx) {
|
||||||
ctx.body = response
|
ctx.body = response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const destroyInternalTablesBySourceId = async datasourceId => {
|
||||||
|
const db = getAppDB()
|
||||||
|
|
||||||
|
// Get all internal tables
|
||||||
|
const internalTables = await db.allDocs(
|
||||||
|
getTableParams(null, {
|
||||||
|
include_docs: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter by datasource and return the docs.
|
||||||
|
const datasourceTableDocs = internalTables.rows.reduce((acc, table) => {
|
||||||
|
if (table.doc.sourceId == datasourceId) {
|
||||||
|
acc.push(table.doc)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Destroy the tables.
|
||||||
|
for (const table of datasourceTableDocs) {
|
||||||
|
await tableDestroy({
|
||||||
|
params: {
|
||||||
|
tableId: table._id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.destroy = async function (ctx) {
|
exports.destroy = async function (ctx) {
|
||||||
const db = getAppDB()
|
const db = getAppDB()
|
||||||
const datasourceId = ctx.params.datasourceId
|
const datasourceId = ctx.params.datasourceId
|
||||||
|
|
||||||
const datasource = await db.get(datasourceId)
|
const datasource = await db.get(datasourceId)
|
||||||
// Delete all queries for the datasource
|
// Delete all queries for the datasource
|
||||||
|
|
||||||
|
if (datasource.type === dbCore.BUDIBASE_DATASOURCE_TYPE) {
|
||||||
|
await destroyInternalTablesBySourceId(datasourceId)
|
||||||
|
} else {
|
||||||
const queries = await db.allDocs(getQueryParams(datasourceId, null))
|
const queries = await db.allDocs(getQueryParams(datasourceId, null))
|
||||||
await db.bulkDocs(
|
await db.bulkDocs(
|
||||||
queries.rows.map(row => ({
|
queries.rows.map(row => ({
|
||||||
|
@ -210,6 +255,7 @@ exports.destroy = async function (ctx) {
|
||||||
_deleted: true,
|
_deleted: true,
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// delete the datasource
|
// delete the datasource
|
||||||
await db.remove(datasourceId, ctx.params.revId)
|
await db.remove(datasourceId, ctx.params.revId)
|
||||||
|
|
|
@ -95,18 +95,7 @@ export function makeSureTableUpToDate(table: any, tableToSave: any) {
|
||||||
return tableToSave
|
return tableToSave
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleDataImport(user: any, table: any, dataImport: any) {
|
export function importToRows(data: any, table: any, user: any = {}) {
|
||||||
if (!dataImport || !dataImport.csvString) {
|
|
||||||
return table
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = getAppDB()
|
|
||||||
// Populate the table with rows imported from CSV in a bulk update
|
|
||||||
const data = await transform({
|
|
||||||
...dataImport,
|
|
||||||
existingTable: table,
|
|
||||||
})
|
|
||||||
|
|
||||||
let finalData: any = []
|
let finalData: any = []
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
let row = data[i]
|
let row = data[i]
|
||||||
|
@ -136,6 +125,22 @@ export async function handleDataImport(user: any, table: any, dataImport: any) {
|
||||||
|
|
||||||
finalData.push(row)
|
finalData.push(row)
|
||||||
}
|
}
|
||||||
|
return finalData
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function handleDataImport(user: any, table: any, dataImport: any) {
|
||||||
|
if (!dataImport || !dataImport.csvString) {
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = getAppDB()
|
||||||
|
// Populate the table with rows imported from CSV in a bulk update
|
||||||
|
const data = await transform({
|
||||||
|
...dataImport,
|
||||||
|
existingTable: table,
|
||||||
|
})
|
||||||
|
|
||||||
|
let finalData: any = importToRows(data, table, user)
|
||||||
|
|
||||||
await quotas.addRows(finalData.length, () => db.bulkDocs(finalData), {
|
await quotas.addRows(finalData.length, () => db.bulkDocs(finalData), {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
|
|
|
@ -0,0 +1,646 @@
|
||||||
|
const {
|
||||||
|
FieldTypes,
|
||||||
|
AutoFieldSubTypes,
|
||||||
|
RelationshipTypes,
|
||||||
|
} = require("../../constants/index")
|
||||||
|
const { importToRows } = require("../../api/controllers/table/utils")
|
||||||
|
const { cloneDeep } = require("lodash/fp")
|
||||||
|
const LinkDocument = require("../linkedRows/LinkDocument")
|
||||||
|
const { inventoryImport } = require("./inventoryImport")
|
||||||
|
const { employeeImport } = require("./employeeImport")
|
||||||
|
const { jobsImport } = require("./jobsImport")
|
||||||
|
const { expensesImport } = require("./expensesImport")
|
||||||
|
const { db: dbCore } = require("@budibase/backend-core")
|
||||||
|
|
||||||
|
exports.DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs"
|
||||||
|
exports.DEFAULT_INVENTORY_TABLE_ID = "ta_bb_inventory"
|
||||||
|
exports.DEFAULT_EXPENSES_TABLE_ID = "ta_bb_expenses"
|
||||||
|
exports.DEFAULT_EMPLOYEE_TABLE_ID = "ta_bb_employee"
|
||||||
|
exports.DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default"
|
||||||
|
exports.DEFAULT_BB_DATASOURCE = {
|
||||||
|
_id: this.DEFAULT_BB_DATASOURCE_ID,
|
||||||
|
type: dbCore.BUDIBASE_DATASOURCE_TYPE,
|
||||||
|
name: "Sample Data",
|
||||||
|
source: "BUDIBASE",
|
||||||
|
config: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncLastIds = (table, rowCount) => {
|
||||||
|
Object.keys(table.schema).forEach(key => {
|
||||||
|
const entry = table.schema[key]
|
||||||
|
if (entry.autocolumn && entry.subtype == "autoID") {
|
||||||
|
entry.lastID = rowCount
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableImport = (table, data) => {
|
||||||
|
const cloneTable = cloneDeep(table)
|
||||||
|
const rowDocs = importToRows(data, cloneTable)
|
||||||
|
syncLastIds(cloneTable, rowDocs.length)
|
||||||
|
return { rows: rowDocs, table: cloneTable }
|
||||||
|
}
|
||||||
|
|
||||||
|
// AUTO COLUMNS
|
||||||
|
const AUTO_COLUMNS = {
|
||||||
|
"Created At": {
|
||||||
|
name: "Created At",
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
subtype: AutoFieldSubTypes.CREATED_AT,
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Updated At": {
|
||||||
|
name: "Updated At",
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
subtype: AutoFieldSubTypes.UPDATED_AT,
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DEFAULT_INVENTORY_TABLE_SCHEMA = {
|
||||||
|
_id: this.DEFAULT_INVENTORY_TABLE_ID,
|
||||||
|
type: "internal",
|
||||||
|
views: {},
|
||||||
|
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||||
|
primaryDisplay: "Item Name",
|
||||||
|
name: "Inventory",
|
||||||
|
schema: {
|
||||||
|
"Item ID": {
|
||||||
|
name: "Item ID",
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
subtype: AutoFieldSubTypes.AUTO_ID,
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: false,
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Item Name": {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {
|
||||||
|
maximum: null,
|
||||||
|
},
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Item Name",
|
||||||
|
},
|
||||||
|
"Item Tags": {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
inclusion: ["Electrical", "Material", "Vehicle", "Office", "Tools"],
|
||||||
|
},
|
||||||
|
name: "Item Tags",
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
Notes: {
|
||||||
|
type: FieldTypes.LONGFORM,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Notes",
|
||||||
|
useRichText: null,
|
||||||
|
},
|
||||||
|
Status: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
inclusion: ["Available", "Repair", "Broken"],
|
||||||
|
},
|
||||||
|
name: "Status",
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
SKU: {
|
||||||
|
type: FieldTypes.BARCODEQR,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "SKU",
|
||||||
|
},
|
||||||
|
"Purchase Date": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Purchase Date",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
"Purchase Price": {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: false,
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: null,
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Purchase Price",
|
||||||
|
},
|
||||||
|
...AUTO_COLUMNS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DEFAULT_EMPLOYEE_TABLE_SCHEMA = {
|
||||||
|
_id: this.DEFAULT_EMPLOYEE_TABLE_ID,
|
||||||
|
type: "internal",
|
||||||
|
views: {},
|
||||||
|
name: "Employees",
|
||||||
|
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||||
|
primaryDisplay: "First Name",
|
||||||
|
schema: {
|
||||||
|
"First Name": {
|
||||||
|
name: "First Name",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Last Name": {
|
||||||
|
name: "Last Name",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Email: {
|
||||||
|
name: "Email",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Address: {
|
||||||
|
name: "Address",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
City: {
|
||||||
|
name: "City",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Postcode: {
|
||||||
|
name: "Postcode",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Phone: {
|
||||||
|
name: "Phone",
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"EMPLOYEE ID": {
|
||||||
|
name: "EMPLOYEE ID",
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
subtype: AutoFieldSubTypes.AUTO_ID,
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: false,
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Employee Level": {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: false,
|
||||||
|
inclusion: ["Manager", "Junior", "Senior", "Apprentice", "Contractor"],
|
||||||
|
},
|
||||||
|
name: "Employee Level",
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
"Badge Photo": {
|
||||||
|
type: "attachment",
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Badge Photo",
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
Jobs: {
|
||||||
|
type: FieldTypes.LINK,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
fieldName: "Assigned",
|
||||||
|
name: "Jobs",
|
||||||
|
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
||||||
|
tableId: this.DEFAULT_JOBS_TABLE_ID,
|
||||||
|
},
|
||||||
|
"Start Date": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Start Date",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
"End Date": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "End Date",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
...AUTO_COLUMNS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DEFAULT_JOBS_TABLE_SCHEMA = {
|
||||||
|
_id: this.DEFAULT_JOBS_TABLE_ID,
|
||||||
|
type: "internal",
|
||||||
|
name: "Jobs",
|
||||||
|
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||||
|
primaryDisplay: "Job ID",
|
||||||
|
schema: {
|
||||||
|
"Job ID": {
|
||||||
|
name: "Job ID",
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
subtype: AutoFieldSubTypes.AUTO_ID,
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: false,
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Quote Date": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Quote Date",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
"Quote Price": {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Quote Price",
|
||||||
|
},
|
||||||
|
"Works Start": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Works Start",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
Address: {
|
||||||
|
type: FieldTypes.LONGFORM,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Address",
|
||||||
|
useRichText: null,
|
||||||
|
},
|
||||||
|
"Customer Name": {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {
|
||||||
|
maximum: null,
|
||||||
|
},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Customer Name",
|
||||||
|
},
|
||||||
|
Notes: {
|
||||||
|
type: FieldTypes.LONGFORM,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Notes",
|
||||||
|
useRichText: null,
|
||||||
|
},
|
||||||
|
"Customer Phone": {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {
|
||||||
|
maximum: null,
|
||||||
|
},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Customer Phone",
|
||||||
|
},
|
||||||
|
"Customer Email": {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {
|
||||||
|
maximum: null,
|
||||||
|
},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Customer Email",
|
||||||
|
},
|
||||||
|
Assigned: {
|
||||||
|
name: "Assigned",
|
||||||
|
type: FieldTypes.LINK,
|
||||||
|
tableId: this.DEFAULT_EMPLOYEE_TABLE_ID,
|
||||||
|
fieldName: "Jobs",
|
||||||
|
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
||||||
|
// sortable: true,
|
||||||
|
},
|
||||||
|
"Works End": {
|
||||||
|
type: "datetime",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Works End",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
"Updated Price": {
|
||||||
|
type: "number",
|
||||||
|
constraints: {
|
||||||
|
type: "number",
|
||||||
|
presence: false,
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Updated Price",
|
||||||
|
},
|
||||||
|
...AUTO_COLUMNS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DEFAULT_EXPENSES_TABLE_SCHEMA = {
|
||||||
|
_id: this.DEFAULT_EXPENSES_TABLE_ID,
|
||||||
|
type: "internal",
|
||||||
|
views: {},
|
||||||
|
name: "Expenses",
|
||||||
|
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||||
|
primaryDisplay: "Expense ID",
|
||||||
|
schema: {
|
||||||
|
"Expense ID": {
|
||||||
|
name: "Expense ID",
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
subtype: AutoFieldSubTypes.AUTO_ID,
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: false,
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Expense Tags": {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
inclusion: [
|
||||||
|
"Fuel",
|
||||||
|
"Food",
|
||||||
|
"Materials",
|
||||||
|
"Repair",
|
||||||
|
"Equipment",
|
||||||
|
"Fees",
|
||||||
|
"Service",
|
||||||
|
"Office",
|
||||||
|
"Other",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
name: "Expense Tags",
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
Cost: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.NUMBER,
|
||||||
|
presence: {
|
||||||
|
allowEmpty: false,
|
||||||
|
},
|
||||||
|
numericality: {
|
||||||
|
greaterThanOrEqualTo: "",
|
||||||
|
lessThanOrEqualTo: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Cost",
|
||||||
|
},
|
||||||
|
Notes: {
|
||||||
|
type: FieldTypes.LONGFORM,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Notes",
|
||||||
|
useRichText: null,
|
||||||
|
},
|
||||||
|
"Payment Due": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Payment Due",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
"Date Paid": {
|
||||||
|
type: FieldTypes.DATETIME,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.STRING,
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
datetime: {
|
||||||
|
latest: "",
|
||||||
|
earliest: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: "Date Paid",
|
||||||
|
ignoreTimezones: true,
|
||||||
|
},
|
||||||
|
Attachment: {
|
||||||
|
type: FieldTypes.ATTACHMENT,
|
||||||
|
constraints: {
|
||||||
|
type: FieldTypes.ARRAY,
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "Attachment",
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
...AUTO_COLUMNS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildDefaultDocs = () => {
|
||||||
|
const inventoryData = tableImport(
|
||||||
|
this.DEFAULT_INVENTORY_TABLE_SCHEMA,
|
||||||
|
inventoryImport
|
||||||
|
)
|
||||||
|
|
||||||
|
const employeeData = tableImport(
|
||||||
|
this.DEFAULT_EMPLOYEE_TABLE_SCHEMA,
|
||||||
|
employeeImport
|
||||||
|
)
|
||||||
|
|
||||||
|
const jobData = tableImport(this.DEFAULT_JOBS_TABLE_SCHEMA, jobsImport)
|
||||||
|
|
||||||
|
const expensesData = tableImport(
|
||||||
|
this.DEFAULT_EXPENSES_TABLE_SCHEMA,
|
||||||
|
expensesImport
|
||||||
|
)
|
||||||
|
|
||||||
|
// Build one link doc for each employee/job
|
||||||
|
const jobEmployeeLinks = employeeData.rows.map((employee, index) => {
|
||||||
|
return new LinkDocument(
|
||||||
|
employeeData.table._id,
|
||||||
|
"Jobs",
|
||||||
|
employeeData.rows[index]._id,
|
||||||
|
jobData.table._id,
|
||||||
|
"Assigned",
|
||||||
|
jobData.rows[index]._id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return [
|
||||||
|
this.DEFAULT_BB_DATASOURCE,
|
||||||
|
inventoryData.table,
|
||||||
|
employeeData.table,
|
||||||
|
jobData.table,
|
||||||
|
expensesData.table,
|
||||||
|
...inventoryData.rows,
|
||||||
|
...employeeData.rows,
|
||||||
|
...jobData.rows,
|
||||||
|
...expensesData.rows,
|
||||||
|
...jobEmployeeLinks,
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
exports.employeeImport = [
|
||||||
|
{
|
||||||
|
"First Name": "Julie",
|
||||||
|
"Last Name": "Jimenez",
|
||||||
|
Email: "julie.jimenez@example.com",
|
||||||
|
Address: "4250 New Street",
|
||||||
|
City: "Stevenage",
|
||||||
|
Postcode: "EE32 3SE",
|
||||||
|
Phone: "01754 13523",
|
||||||
|
"Created At": "2022-11-10T17:56:18.353Z",
|
||||||
|
"Updated At": "2022-11-10T18:32:15.298Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Senior"],
|
||||||
|
"Start Date": "2015-02-12T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Mandy",
|
||||||
|
"Last Name": "Clark",
|
||||||
|
Email: "mandy.clark@example.com",
|
||||||
|
Address: "8632 North Street",
|
||||||
|
City: "Hereford",
|
||||||
|
Postcode: "GT81 7DG",
|
||||||
|
Phone: "016973 32814",
|
||||||
|
"Created At": "2022-11-10T17:56:18.353Z",
|
||||||
|
"Updated At": "2022-11-10T18:31:44.928Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Senior"],
|
||||||
|
"Start Date": "2017-09-10T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Holly",
|
||||||
|
"Last Name": "Carroll",
|
||||||
|
Email: "holly.carroll@example.com",
|
||||||
|
Address: "5976 Springfield Road",
|
||||||
|
City: "Edinburgh",
|
||||||
|
Postcode: "Y4 2LH",
|
||||||
|
Phone: "016977 73053",
|
||||||
|
"Created At": "2022-11-10T17:56:18.356Z",
|
||||||
|
"Updated At": "2022-11-10T18:31:32.086Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Senior"],
|
||||||
|
"Start Date": "2022-02-12T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Francis",
|
||||||
|
"Last Name": "Castro",
|
||||||
|
Email: "francis.castro@example.com",
|
||||||
|
Address: "3970 High Street",
|
||||||
|
City: "Wells",
|
||||||
|
Postcode: "X12 6QA",
|
||||||
|
Phone: "017684 23551",
|
||||||
|
"Created At": "2022-11-10T17:56:18.357Z",
|
||||||
|
"Updated At": "2022-11-10T18:31:16.976Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Apprentice"],
|
||||||
|
"Start Date": "2021-03-10T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Richard",
|
||||||
|
"Last Name": "Kelley",
|
||||||
|
Email: "richard.kelley@example.com",
|
||||||
|
Address: "2346 York Road",
|
||||||
|
City: "Leicester",
|
||||||
|
Postcode: "H7S 1AH",
|
||||||
|
Phone: "013873 65167",
|
||||||
|
"Created At": "2022-11-10T17:56:18.353Z",
|
||||||
|
"Updated At": "2022-11-10T18:32:23.314Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Apprentice"],
|
||||||
|
"Start Date": "2020-07-09T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Donald",
|
||||||
|
"Last Name": "Lynch",
|
||||||
|
Email: "donald.lynch@example.com",
|
||||||
|
Address: "9642 New Road",
|
||||||
|
City: "St Albans",
|
||||||
|
Postcode: "V9A 1NP",
|
||||||
|
Phone: "015242 46760",
|
||||||
|
"Created At": "2022-11-10T17:56:18.352Z",
|
||||||
|
"Updated At": "2022-11-10T18:30:38.439Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Junior"],
|
||||||
|
"Start Date": "2018-04-13T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Maria",
|
||||||
|
"Last Name": "Torres",
|
||||||
|
Email: "maria.torres@example.com",
|
||||||
|
Address: "9998 New Road",
|
||||||
|
City: "Aberdeen",
|
||||||
|
Postcode: "LP7 8JQ",
|
||||||
|
Phone: "0101 472 3365",
|
||||||
|
"Created At": "2022-11-10T17:56:18.353Z",
|
||||||
|
"Updated At": "2022-11-10T18:31:37.748Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Manager"],
|
||||||
|
"Start Date": "2016-05-22T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Suzy",
|
||||||
|
"Last Name": "Ruiz",
|
||||||
|
Email: "suzy.ruiz@example.com",
|
||||||
|
Address: "4641 Victoria Street",
|
||||||
|
City: "Armagh",
|
||||||
|
Postcode: "MO4X 8BP",
|
||||||
|
Phone: "015242 79977",
|
||||||
|
"Created At": "2022-11-10T17:56:18.354Z",
|
||||||
|
"Updated At": "2022-11-10T18:58:54.632Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Senior", "Manager"],
|
||||||
|
"Start Date": "2019-05-01T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Patrick",
|
||||||
|
"Last Name": "Garcia",
|
||||||
|
Email: "patrick.garcia@example.com",
|
||||||
|
Address: "7818 The Crescent",
|
||||||
|
City: "Bath",
|
||||||
|
Postcode: "OH5 3HE",
|
||||||
|
Phone: "017683 02608",
|
||||||
|
"Created At": "2022-11-10T17:56:18.353Z",
|
||||||
|
"Updated At": "2022-11-10T18:31:06.820Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Apprentice"],
|
||||||
|
"Start Date": "2014-08-30T12:00:00.000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"First Name": "Brayden",
|
||||||
|
"Last Name": "Carpenter",
|
||||||
|
Email: "brayden.carpenter@example.com",
|
||||||
|
Address: "8755 The Drive",
|
||||||
|
City: "Bradford",
|
||||||
|
Postcode: "YH5 8RY",
|
||||||
|
Phone: "015395 12426",
|
||||||
|
"Created At": "2022-11-10T17:56:18.354Z",
|
||||||
|
"Updated At": "2022-11-10T20:41:26.977Z",
|
||||||
|
tableId: "ta_bb_employees",
|
||||||
|
type: "row",
|
||||||
|
"Employee Level": ["Contractor"],
|
||||||
|
"Start Date": "2022-11-09T12:00:00.000",
|
||||||
|
},
|
||||||
|
]
|
|
@ -0,0 +1,114 @@
|
||||||
|
exports.expensesImport = [
|
||||||
|
{
|
||||||
|
"Date Paid": "2022-11-12T12:00:00.000",
|
||||||
|
"Payment Due": "2022-11-01T12:00:00.000",
|
||||||
|
Cost: 117.4,
|
||||||
|
Notes: "Two vans needed a top up",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T19:07:14.714Z",
|
||||||
|
"Updated At": "2022-11-10T20:02:14.440Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Fuel", "Equipment"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Date Paid": "2022-11-11T12:00:00.000",
|
||||||
|
Cost: 217,
|
||||||
|
Notes: "3 branded work bags and safety equipment for the new hires",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T19:10:35.459Z",
|
||||||
|
"Updated At": "2022-11-10T19:10:35.459Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Materials"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Date Paid": "2022-11-25T12:00:00.000",
|
||||||
|
Cost: 420.68,
|
||||||
|
Notes: "Monthly games night",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T19:20:08.264Z",
|
||||||
|
"Updated At": "2022-11-10T19:27:14.141Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Food"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Date Paid": "2022-11-24T12:00:00.000",
|
||||||
|
"Payment Due": "2022-11-24T12:00:00.000",
|
||||||
|
Cost: 45,
|
||||||
|
Notes: "Work van",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T18:20:16.709Z",
|
||||||
|
"Updated At": "2022-11-10T20:02:05.293Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Fuel", "Equipment"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Payment Due": "2022-11-25T12:00:00.000",
|
||||||
|
Cost: 200,
|
||||||
|
Notes: "Accountant payroll management",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T19:06:16.014Z",
|
||||||
|
"Updated At": "2022-11-10T19:06:16.014Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Fees", "Service"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Payment Due": "2022-11-26T12:00:00.000",
|
||||||
|
Cost: 28,
|
||||||
|
Notes: "Circular saw needed a new plug",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T20:03:18.051Z",
|
||||||
|
"Updated At": "2022-11-10T20:03:18.051Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Equipment", "Repair"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Payment Due": "2022-11-11T12:00:00.000",
|
||||||
|
Cost: 131.75,
|
||||||
|
Notes: "Solicitor contract reviews for employees",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T18:56:16.111Z",
|
||||||
|
"Updated At": "2022-11-10T19:20:58.681Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Fees", "Service"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Cost: 2500,
|
||||||
|
Notes: "New Laptop for the office. ",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T18:04:11.401Z",
|
||||||
|
"Updated At": "2022-11-10T20:08:16.459Z",
|
||||||
|
type: "row",
|
||||||
|
"Date Paid": "2022-11-09T12:00:00.000",
|
||||||
|
"Expense Tags": ["Equipment"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Date Paid": "2022-10-25T12:00:00.000",
|
||||||
|
Cost: 275,
|
||||||
|
Notes: "Accountant payroll. Added new hire",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T20:01:31.783Z",
|
||||||
|
"Updated At": "2022-11-10T20:01:31.783Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Fees", "Service"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Payment Due": "2022-11-19T12:00:00.000",
|
||||||
|
Cost: 250,
|
||||||
|
Notes: "200 new branded pens and 40 beanie hats. ",
|
||||||
|
Attachment: [],
|
||||||
|
tableId: "ta_bb_expenses",
|
||||||
|
"Created At": "2022-11-10T19:09:08.074Z",
|
||||||
|
"Updated At": "2022-11-10T19:09:08.074Z",
|
||||||
|
type: "row",
|
||||||
|
"Expense Tags": ["Service"],
|
||||||
|
},
|
||||||
|
]
|
|
@ -0,0 +1,106 @@
|
||||||
|
exports.inventoryImport = [
|
||||||
|
{
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Little Blue Van",
|
||||||
|
SKU: "",
|
||||||
|
Notes: "MAX PAYLOAD 595 kg \nMAX LOAD LENGTH 1620 mm",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T19:11:40.141Z",
|
||||||
|
"Updated At": "2022-11-10T20:05:04.608Z",
|
||||||
|
type: "row",
|
||||||
|
"Purchase Date": "2022-10-10T12:00:00.000",
|
||||||
|
"Purchase Price": 39995,
|
||||||
|
"Item Tags": ["Vehicle"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Masonry Drill",
|
||||||
|
SKU: "ABC-123",
|
||||||
|
Notes: "Making a burning smell",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T18:46:10.820Z",
|
||||||
|
"Updated At": "2022-11-10T20:11:23.766Z",
|
||||||
|
type: "row",
|
||||||
|
"Purchase Date": "1992-11-19T12:00:00.000",
|
||||||
|
"Item Tags": ["Electrical", "Tools"],
|
||||||
|
"Purchase Price": 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: ["Repair"],
|
||||||
|
"Item Name": "Circular saw",
|
||||||
|
SKU: "AB2-100",
|
||||||
|
Notes: "",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T19:04:38.805Z",
|
||||||
|
"Updated At": "2022-11-10T20:20:24.000Z",
|
||||||
|
type: "row",
|
||||||
|
"Purchase Date": "2012-11-15T12:00:00.000",
|
||||||
|
"Item Tags": ["Electrical"],
|
||||||
|
"Purchase Price": 300,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Item Tags": ["Electrical"],
|
||||||
|
"Purchase Price": 210,
|
||||||
|
"Purchase Date": "2022-10-17T12:00:00.000",
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Tablet Device (5g)",
|
||||||
|
SKU: "PH-001",
|
||||||
|
Notes: "Android tablet for use on site",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T20:21:56.332Z",
|
||||||
|
"Updated At": "2022-11-10T20:21:56.332Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Item Tags": ["Tools", "Electrical"],
|
||||||
|
"Purchase Price": 200,
|
||||||
|
"Purchase Date": "2022-10-12T12:00:00.000",
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Power Screwdriver",
|
||||||
|
SKU: "TKIT-002-A",
|
||||||
|
Notes: "",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T20:10:51.129Z",
|
||||||
|
"Updated At": "2022-11-10T20:13:37.821Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Large Blue Van",
|
||||||
|
SKU: "",
|
||||||
|
Notes: "MAX LOAD LENGTH 4256 mm",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T19:03:41.698Z",
|
||||||
|
"Updated At": "2022-11-10T20:04:57.932Z",
|
||||||
|
type: "row",
|
||||||
|
"Purchase Date": "2022-10-10T12:00:00.000",
|
||||||
|
"Purchase Price": 65995,
|
||||||
|
"Item Tags": ["Vehicle"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Purchase Price": 2500,
|
||||||
|
"Purchase Date": "2022-11-09T12:00:00.000",
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Office Laptop",
|
||||||
|
SKU: "PC-123-ABC",
|
||||||
|
Notes: "Office Laptop \n",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T20:06:14.463Z",
|
||||||
|
"Updated At": "2022-11-10T20:07:02.532Z",
|
||||||
|
type: "row",
|
||||||
|
"Item Tags": ["Electrical", "Office"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: ["Available"],
|
||||||
|
"Item Name": "Little Red Van",
|
||||||
|
SKU: "",
|
||||||
|
Notes: "MAX PAYLOAD 595 kg \nMAX LOAD LENGTH 1620 mm",
|
||||||
|
tableId: "ta_bb_inventory",
|
||||||
|
"Created At": "2022-11-10T19:55:02.367Z",
|
||||||
|
"Updated At": "2022-11-10T20:05:13.504Z",
|
||||||
|
type: "row",
|
||||||
|
"Purchase Date": "2022-07-17T12:00:00.000",
|
||||||
|
"Purchase Price": 39995,
|
||||||
|
"Item Tags": ["Vehicle"],
|
||||||
|
},
|
||||||
|
]
|
|
@ -0,0 +1,158 @@
|
||||||
|
exports.jobsImport = [
|
||||||
|
{
|
||||||
|
"Works End": "2023-01-28T12:00:00.000",
|
||||||
|
"Customer Email": "susie.peterson@example.com",
|
||||||
|
"Customer Phone": "016973 88386",
|
||||||
|
Notes:
|
||||||
|
"Bring the large van as recycling has been requested. \nAlso, they have a large dog.",
|
||||||
|
"Customer Name": "Susie Peterson",
|
||||||
|
Address: "5452 The Crescent\nBrighton and Hove\nAI7G 7BN",
|
||||||
|
"Works Start": "2023-01-26T12:00:00.000",
|
||||||
|
"Quote Price": 4200,
|
||||||
|
"Quote Date": "2022-11-11T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T18:00:29.510Z",
|
||||||
|
"Updated At": "2022-11-10T20:37:45.120Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Updated Price": 307,
|
||||||
|
"Works End": "2022-11-19T12:00:00.000",
|
||||||
|
"Customer Email": "micheal.murphy@example.co",
|
||||||
|
"Customer Phone": "07344 867816",
|
||||||
|
Notes:
|
||||||
|
"Adding new utils and tearing down the dividing walls. Bring large blue van.\n\nThe customer can be difficult. Avoid",
|
||||||
|
"Customer Name": "Micheal Murphy",
|
||||||
|
Address: "5266 York Road\nOxford\nG2 8EP",
|
||||||
|
"Works Start": "2022-11-10T12:00:00.000",
|
||||||
|
"Quote Price": 1231,
|
||||||
|
"Quote Date": "2022-10-04T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T20:53:39.882Z",
|
||||||
|
"Updated At": "2022-11-10T20:59:49.435Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Customer Email": "",
|
||||||
|
"Customer Phone": "07374 594595",
|
||||||
|
Notes:
|
||||||
|
"Removal and recycle requested of all units.\n\nStill awaiting feedback. If this is still around after next wednesday, just delete it.",
|
||||||
|
"Customer Name": "Charlotte Carpenter",
|
||||||
|
Address: "7780 Mill Lane\nGreater Manchester\nDU57 3GA",
|
||||||
|
"Quote Price": 500,
|
||||||
|
"Quote Date": "2022-11-08T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T21:03:11.782Z",
|
||||||
|
"Updated At": "2022-11-10T21:03:11.782Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Updated Price": 2001,
|
||||||
|
"Works End": "2022-11-16T12:00:00.000",
|
||||||
|
"Customer Email": "leah.freeman@example.com",
|
||||||
|
"Customer Phone": "07844 42134",
|
||||||
|
Notes:
|
||||||
|
"Original quote too high. Material costs dropped.\nFull system installation.",
|
||||||
|
"Customer Name": "Leah Freeman",
|
||||||
|
Address: "4252 Fairview Road\nChester\nW62 7JH",
|
||||||
|
"Works Start": "2022-11-09T12:00:00.000",
|
||||||
|
"Quote Price": 3000,
|
||||||
|
"Quote Date": "2022-10-04T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T20:25:44.284Z",
|
||||||
|
"Updated At": "2022-11-10T20:54:21.655Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Works End": "2022-11-13T12:00:00.000",
|
||||||
|
"Customer Email": "scarlett.gibson@example.co",
|
||||||
|
"Customer Phone": "07572 745859",
|
||||||
|
Notes:
|
||||||
|
"This address has a service dog.\n\nQuote didn't account for a sinkhole at the property. Amended",
|
||||||
|
"Customer Name": "Scarlett Gibson",
|
||||||
|
Address: "5624 The Drive\nArmagh\nNU0 5DW",
|
||||||
|
"Works Start": "2022-11-12T12:00:00.000",
|
||||||
|
"Quote Price": 120,
|
||||||
|
"Quote Date": "2022-11-11T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T19:50:55.215Z",
|
||||||
|
"Updated At": "2022-11-10T20:44:12.004Z",
|
||||||
|
type: "row",
|
||||||
|
"Updated Price": 175,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Customer Email": "lester.rose@example.com",
|
||||||
|
"Customer Phone": "07103 009138",
|
||||||
|
Notes: "4 Radiators Removed\nMany cats in the house",
|
||||||
|
"Customer Name": "Lester Rose",
|
||||||
|
Address: "8543 Albert Road\nNewport\nLancashire\nUnited Kingdom\nS58 5YW",
|
||||||
|
"Quote Price": 3543,
|
||||||
|
"Quote Date": "2022-11-10T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T18:43:21.110Z",
|
||||||
|
"Updated At": "2022-11-10T20:40:48.241Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Works End": "2022-11-24T12:00:00.000",
|
||||||
|
"Customer Email": "joel.owens@example.com",
|
||||||
|
"Customer Phone": "07216 548317",
|
||||||
|
Notes:
|
||||||
|
"Full retrofit of current installation. Will need big blue van. \n\nThere's a decent coffee place nearby. Ensure you buy enough for everyone.",
|
||||||
|
"Customer Name": "Joel Owens",
|
||||||
|
Address: "5516 Oaks Cross\nNewry\nT6V 9SL",
|
||||||
|
"Works Start": "2022-11-24T12:00:00.000",
|
||||||
|
"Quote Price": 789,
|
||||||
|
"Quote Date": "2022-11-10T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T21:07:28.365Z",
|
||||||
|
"Updated At": "2022-11-10T21:08:18.661Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Customer Email": "freddie.franklin@example.com",
|
||||||
|
"Customer Phone": "016977 48298",
|
||||||
|
Notes:
|
||||||
|
"Equipment updates and some general maintenance.\n\nHouse has 3 walls.",
|
||||||
|
"Customer Name": "Freddie Franklin",
|
||||||
|
Address: "2035 Brick Kiln Road\nCoventry\nTS81 7AW",
|
||||||
|
"Quote Price": 302,
|
||||||
|
"Quote Date": "2022-11-10T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T18:33:57.850Z",
|
||||||
|
"Updated At": "2022-11-10T20:57:54.015Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Works End": "2022-11-12T12:00:00.000",
|
||||||
|
"Customer Email": "diane.henry@example.com",
|
||||||
|
"Customer Phone": "07635 514491",
|
||||||
|
Notes: "Large van required, recycling requested. \nNew customer",
|
||||||
|
"Customer Name": "Diane Henry",
|
||||||
|
Address:
|
||||||
|
"3518 Station Road\nSunderland\nCounty Down\nUnited Kingdom\nXC67 8ES",
|
||||||
|
"Works Start": "2022-11-11T12:00:00.000",
|
||||||
|
"Quote Price": 2039,
|
||||||
|
"Quote Date": "2022-11-10T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T19:23:08.036Z",
|
||||||
|
"Updated At": "2022-11-10T20:45:40.523Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Works End": "2022-09-23T12:00:00.000",
|
||||||
|
"Customer Email": "warren.alvarez@example.com",
|
||||||
|
"Customer Phone": "07768 90794",
|
||||||
|
Notes:
|
||||||
|
"System restoration and upgrades. \nCustomer is a smoker, bring cleaning equipment",
|
||||||
|
"Customer Name": "Warren Alvarez",
|
||||||
|
Address: "867 High Street\nBath\nKF8 6ZS",
|
||||||
|
"Works Start": "2022-09-23T12:00:00.000",
|
||||||
|
"Quote Price": 1412,
|
||||||
|
"Quote Date": "2022-09-20T12:00:00.000",
|
||||||
|
tableId: "ta_bb_jobs",
|
||||||
|
"Created At": "2022-11-10T20:57:00.124Z",
|
||||||
|
"Updated At": "2022-11-10T21:08:00.446Z",
|
||||||
|
type: "row",
|
||||||
|
},
|
||||||
|
]
|
|
@ -1,55 +1,9 @@
|
||||||
const { IncludeDocs, getLinkDocuments } = require("./linkUtils")
|
const { IncludeDocs, getLinkDocuments } = require("./linkUtils")
|
||||||
const {
|
const { InternalTables, getUserMetadataParams } = require("../utils")
|
||||||
generateLinkID,
|
|
||||||
InternalTables,
|
|
||||||
getUserMetadataParams,
|
|
||||||
} = require("../utils")
|
|
||||||
const Sentry = require("@sentry/node")
|
const Sentry = require("@sentry/node")
|
||||||
const { FieldTypes, RelationshipTypes } = require("../../constants")
|
const { FieldTypes, RelationshipTypes } = require("../../constants")
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
const { getAppDB } = require("@budibase/backend-core/context")
|
||||||
|
const LinkDocument = require("./LinkDocument")
|
||||||
/**
|
|
||||||
* Creates a new link document structure which can be put to the database. It is important to
|
|
||||||
* note that while this talks about linker/linked the link is bi-directional and for all intent
|
|
||||||
* and purposes it does not matter from which direction the link was initiated.
|
|
||||||
* @param {string} tableId1 The ID of the first table (the linker).
|
|
||||||
* @param {string} tableId2 The ID of the second table (the linked).
|
|
||||||
* @param {string} fieldName1 The name of the field in the linker table.
|
|
||||||
* @param {string} fieldName2 The name of the field in the linked table.
|
|
||||||
* @param {string} rowId1 The ID of the row which is acting as the linker.
|
|
||||||
* @param {string} rowId2 The ID of the row which is acting as the linked.
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function LinkDocument(
|
|
||||||
tableId1,
|
|
||||||
fieldName1,
|
|
||||||
rowId1,
|
|
||||||
tableId2,
|
|
||||||
fieldName2,
|
|
||||||
rowId2
|
|
||||||
) {
|
|
||||||
// build the ID out of unique references to this link document
|
|
||||||
this._id = generateLinkID(
|
|
||||||
tableId1,
|
|
||||||
tableId2,
|
|
||||||
rowId1,
|
|
||||||
rowId2,
|
|
||||||
fieldName1,
|
|
||||||
fieldName2
|
|
||||||
)
|
|
||||||
// required for referencing in view
|
|
||||||
this.type = FieldTypes.LINK
|
|
||||||
this.doc1 = {
|
|
||||||
tableId: tableId1,
|
|
||||||
fieldName: fieldName1,
|
|
||||||
rowId: rowId1,
|
|
||||||
}
|
|
||||||
this.doc2 = {
|
|
||||||
tableId: tableId2,
|
|
||||||
fieldName: fieldName2,
|
|
||||||
rowId: rowId2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LinkController {
|
class LinkController {
|
||||||
constructor({ tableId, row, table, oldTable }) {
|
constructor({ tableId, row, table, oldTable }) {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
const { generateLinkID } = require("../utils")
|
||||||
|
const { FieldTypes } = require("../../constants")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new link document structure which can be put to the database. It is important to
|
||||||
|
* note that while this talks about linker/linked the link is bi-directional and for all intent
|
||||||
|
* and purposes it does not matter from which direction the link was initiated.
|
||||||
|
* @param {string} tableId1 The ID of the first table (the linker).
|
||||||
|
* @param {string} tableId2 The ID of the second table (the linked).
|
||||||
|
* @param {string} fieldName1 The name of the field in the linker table.
|
||||||
|
* @param {string} fieldName2 The name of the field in the linked table.
|
||||||
|
* @param {string} rowId1 The ID of the row which is acting as the linker.
|
||||||
|
* @param {string} rowId2 The ID of the row which is acting as the linked.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LinkDocument(
|
||||||
|
tableId1,
|
||||||
|
fieldName1,
|
||||||
|
rowId1,
|
||||||
|
tableId2,
|
||||||
|
fieldName2,
|
||||||
|
rowId2
|
||||||
|
) {
|
||||||
|
// build the ID out of unique references to this link document
|
||||||
|
this._id = generateLinkID(
|
||||||
|
tableId1,
|
||||||
|
tableId2,
|
||||||
|
rowId1,
|
||||||
|
rowId2,
|
||||||
|
fieldName1,
|
||||||
|
fieldName2
|
||||||
|
)
|
||||||
|
// required for referencing in view
|
||||||
|
this.type = FieldTypes.LINK
|
||||||
|
this.doc1 = {
|
||||||
|
tableId: tableId1,
|
||||||
|
fieldName: fieldName1,
|
||||||
|
rowId: rowId1,
|
||||||
|
}
|
||||||
|
this.doc2 = {
|
||||||
|
tableId: tableId2,
|
||||||
|
fieldName: fieldName2,
|
||||||
|
rowId: rowId2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LinkDocument
|
|
@ -15,7 +15,7 @@ export const SearchIndexes = {
|
||||||
|
|
||||||
export const BudibaseInternalDB = {
|
export const BudibaseInternalDB = {
|
||||||
_id: "bb_internal",
|
_id: "bb_internal",
|
||||||
type: "budibase",
|
type: dbCore.BUDIBASE_DATASOURCE_TYPE,
|
||||||
name: "Budibase DB",
|
name: "Budibase DB",
|
||||||
source: "BUDIBASE",
|
source: "BUDIBASE",
|
||||||
config: {},
|
config: {},
|
||||||
|
|
|
@ -19,7 +19,7 @@ async function getAllInternalTables(db?: Database): Promise<Table[]> {
|
||||||
return internalTables.rows.map((tableDoc: any) => ({
|
return internalTables.rows.map((tableDoc: any) => ({
|
||||||
...tableDoc.doc,
|
...tableDoc.doc,
|
||||||
type: "internal",
|
type: "internal",
|
||||||
sourceId: BudibaseInternalDB._id,
|
sourceId: tableDoc.doc.sourceId || BudibaseInternalDB._id,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ const controller = require("../../controllers/global/configs")
|
||||||
const { joiValidator } = require("@budibase/backend-core/auth")
|
const { joiValidator } = require("@budibase/backend-core/auth")
|
||||||
const { adminOnly } = require("@budibase/backend-core/auth")
|
const { adminOnly } = require("@budibase/backend-core/auth")
|
||||||
const Joi = require("joi")
|
const Joi = require("joi")
|
||||||
const { Config } = require("../../../constants")
|
const { Config } = require("@budibase/backend-core/constants")
|
||||||
|
|
||||||
const router = new Router()
|
const router = new Router()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue