commit
078d327cd0
|
@ -59,6 +59,13 @@
|
||||||
|
|
||||||
// If time only set date component to 2000-01-01
|
// If time only set date component to 2000-01-01
|
||||||
if (timeOnly) {
|
if (timeOnly) {
|
||||||
|
// Classic flackpickr causing issues.
|
||||||
|
// When selecting a value for the first time for a "time only" field,
|
||||||
|
// the time is always offset by 1 hour for some reason (regardless of time
|
||||||
|
// zone) so we need to correct it.
|
||||||
|
if (!value && newValue) {
|
||||||
|
newValue = new Date(dates[0].getTime() + 60 * 60 * 1000).toISOString()
|
||||||
|
}
|
||||||
newValue = `2000-01-01T${newValue.split("T")[1]}`
|
newValue = `2000-01-01T${newValue.split("T")[1]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,13 @@
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="filename">
|
<div class="filename">
|
||||||
{#if selectedUrl}
|
{#if selectedUrl}
|
||||||
<Link href={selectedUrl}>{selectedImage.name}</Link>
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
download={selectedImage.name}
|
||||||
|
href={selectedUrl}
|
||||||
|
>
|
||||||
|
{selectedImage.name}
|
||||||
|
</Link>
|
||||||
{:else}
|
{:else}
|
||||||
{selectedImage.name}
|
{selectedImage.name}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -8,12 +8,14 @@
|
||||||
export let secondary = false
|
export let secondary = false
|
||||||
export let overBackground = false
|
export let overBackground = false
|
||||||
export let target
|
export let target
|
||||||
|
export let download
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
on:click
|
on:click
|
||||||
{href}
|
{href}
|
||||||
{target}
|
{target}
|
||||||
|
{download}
|
||||||
class:spectrum-Link--primary={primary}
|
class:spectrum-Link--primary={primary}
|
||||||
class:spectrum-Link--secondary={secondary}
|
class:spectrum-Link--secondary={secondary}
|
||||||
class:spectrum-Link--overBackground={overBackground}
|
class:spectrum-Link--overBackground={overBackground}
|
||||||
|
|
|
@ -15,14 +15,24 @@
|
||||||
|
|
||||||
{#each attachments as attachment}
|
{#each attachments as attachment}
|
||||||
{#if isImage(attachment.extension)}
|
{#if isImage(attachment.extension)}
|
||||||
<Link quiet target="_blank" href={attachment.url}>
|
<Link
|
||||||
|
quiet
|
||||||
|
target="_blank"
|
||||||
|
download={attachment.name}
|
||||||
|
href={attachment.url}
|
||||||
|
>
|
||||||
<div class="center" title={attachment.name}>
|
<div class="center" title={attachment.name}>
|
||||||
<img src={attachment.url} alt={attachment.extension} />
|
<img src={attachment.url} alt={attachment.extension} />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="file" title={attachment.name}>
|
<div class="file" title={attachment.name}>
|
||||||
<Link quiet target="_blank" href={attachment.url}>
|
<Link
|
||||||
|
quiet
|
||||||
|
target="_blank"
|
||||||
|
download={attachment.name}
|
||||||
|
href={attachment.url}
|
||||||
|
>
|
||||||
{attachment.extension}
|
{attachment.extension}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -186,7 +186,7 @@
|
||||||
$goto("./navigation")
|
$goto("./navigation")
|
||||||
}
|
}
|
||||||
} else if (type === "request-add-component") {
|
} else if (type === "request-add-component") {
|
||||||
$goto(`./components/${$selectedComponent?._id}/new`)
|
toggleAddComponent()
|
||||||
} else if (type === "highlight-setting") {
|
} else if (type === "highlight-setting") {
|
||||||
store.actions.settings.highlight(data.setting)
|
store.actions.settings.highlight(data.setting)
|
||||||
|
|
||||||
|
@ -230,9 +230,8 @@
|
||||||
if (isAddingComponent) {
|
if (isAddingComponent) {
|
||||||
$goto(`../${$selectedScreen._id}/components/${$selectedComponent?._id}`)
|
$goto(`../${$selectedScreen._id}/components/${$selectedComponent?._id}`)
|
||||||
} else {
|
} else {
|
||||||
$goto(
|
const id = $selectedComponent?._id || $selectedScreen?.props?._id
|
||||||
`../${$selectedScreen._id}/components/${$selectedComponent?._id}/new`
|
$goto(`../${$selectedScreen._id}/components/${id}/new`)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ const cleanupQuery = query => {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (let [key, value] of Object.entries(query[filterField])) {
|
for (let [key, value] of Object.entries(query[filterField])) {
|
||||||
if (!value || value === "") {
|
if (value == null || value === "") {
|
||||||
delete query[filterField][key]
|
delete query[filterField][key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ export const runLuceneQuery = (docs, query) => {
|
||||||
return docs
|
return docs
|
||||||
}
|
}
|
||||||
|
|
||||||
// make query consistent first
|
// Make query consistent first
|
||||||
query = cleanupQuery(query)
|
query = cleanupQuery(query)
|
||||||
|
|
||||||
// Iterates over a set of filters and evaluates a fail function against a doc
|
// Iterates over a set of filters and evaluates a fail function against a doc
|
||||||
|
@ -206,7 +206,12 @@ export const runLuceneQuery = (docs, query) => {
|
||||||
|
|
||||||
// Process a range match
|
// Process a range match
|
||||||
const rangeMatch = match("range", (docValue, testValue) => {
|
const rangeMatch = match("range", (docValue, testValue) => {
|
||||||
return !docValue || docValue < testValue.low || docValue > testValue.high
|
return (
|
||||||
|
docValue == null ||
|
||||||
|
docValue === "" ||
|
||||||
|
docValue < testValue.low ||
|
||||||
|
docValue > testValue.high
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Process an equal match (fails if the value is different)
|
// Process an equal match (fails if the value is different)
|
||||||
|
|
|
@ -375,6 +375,7 @@ exports.exportRows = async ctx => {
|
||||||
const table = await db.get(ctx.params.tableId)
|
const table = await db.get(ctx.params.tableId)
|
||||||
const rowIds = ctx.request.body.rows
|
const rowIds = ctx.request.body.rows
|
||||||
let format = ctx.query.format
|
let format = ctx.query.format
|
||||||
|
const { columns } = ctx.request.body
|
||||||
let response = (
|
let response = (
|
||||||
await db.allDocs({
|
await db.allDocs({
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
|
@ -382,7 +383,20 @@ exports.exportRows = async ctx => {
|
||||||
})
|
})
|
||||||
).rows.map(row => row.doc)
|
).rows.map(row => row.doc)
|
||||||
|
|
||||||
let rows = await outputProcessing(table, response)
|
let result = await outputProcessing(table, response)
|
||||||
|
let rows = []
|
||||||
|
|
||||||
|
// Filter data to only specified columns if required
|
||||||
|
if (columns && columns.length) {
|
||||||
|
for (let i = 0; i < result.length; i++) {
|
||||||
|
rows[i] = {}
|
||||||
|
for (let column of columns) {
|
||||||
|
rows[i][column] = result[i][column]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rows = result
|
||||||
|
}
|
||||||
|
|
||||||
let headers = Object.keys(rows[0])
|
let headers = Object.keys(rows[0])
|
||||||
const exporter = exporters[format]
|
const exporter = exporters[format]
|
||||||
|
|
|
@ -3,7 +3,12 @@ const setup = require("./utilities")
|
||||||
const { basicRow } = setup.structures
|
const { basicRow } = setup.structures
|
||||||
const { doInAppContext } = require("@budibase/backend-core/context")
|
const { doInAppContext } = require("@budibase/backend-core/context")
|
||||||
const { doInTenant } = require("@budibase/backend-core/tenancy")
|
const { doInTenant } = require("@budibase/backend-core/tenancy")
|
||||||
const { quotas, QuotaUsageType, StaticQuotaName, MonthlyQuotaName } = require("@budibase/pro")
|
const {
|
||||||
|
quotas,
|
||||||
|
QuotaUsageType,
|
||||||
|
StaticQuotaName,
|
||||||
|
MonthlyQuotaName,
|
||||||
|
} = require("@budibase/pro")
|
||||||
|
|
||||||
describe("/rows", () => {
|
describe("/rows", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
|
@ -23,23 +28,30 @@ describe("/rows", () => {
|
||||||
await request
|
await request
|
||||||
.get(`/api/${table._id}/rows/${id}`)
|
.get(`/api/${table._id}/rows/${id}`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(status)
|
.expect(status)
|
||||||
|
|
||||||
const getRowUsage = async () => {
|
const getRowUsage = async () => {
|
||||||
return config.doInContext(null, () => quotas.getCurrentUsageValue(QuotaUsageType.STATIC, StaticQuotaName.ROWS))
|
return config.doInContext(null, () =>
|
||||||
|
quotas.getCurrentUsageValue(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getQueryUsage = async () => {
|
const getQueryUsage = async () => {
|
||||||
return config.doInContext(null, () => quotas.getCurrentUsageValue(QuotaUsageType.MONTHLY, MonthlyQuotaName.QUERIES))
|
return config.doInContext(null, () =>
|
||||||
|
quotas.getCurrentUsageValue(
|
||||||
|
QuotaUsageType.MONTHLY,
|
||||||
|
MonthlyQuotaName.QUERIES
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const assertRowUsage = async (expected) => {
|
const assertRowUsage = async expected => {
|
||||||
const usage = await getRowUsage()
|
const usage = await getRowUsage()
|
||||||
expect(usage).toBe(expected)
|
expect(usage).toBe(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
const assertQueryUsage = async (expected) => {
|
const assertQueryUsage = async expected => {
|
||||||
const usage = await getQueryUsage()
|
const usage = await getQueryUsage()
|
||||||
expect(usage).toBe(expected)
|
expect(usage).toBe(expected)
|
||||||
}
|
}
|
||||||
|
@ -76,10 +88,12 @@ describe("/rows", () => {
|
||||||
name: "Updated Name",
|
name: "Updated Name",
|
||||||
})
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`)
|
expect(res.res.statusMessage).toEqual(
|
||||||
|
`${table.name} updated successfully.`
|
||||||
|
)
|
||||||
expect(res.body.name).toEqual("Updated Name")
|
expect(res.body.name).toEqual("Updated Name")
|
||||||
// await assertRowUsage(rowUsage)
|
// await assertRowUsage(rowUsage)
|
||||||
// await assertQueryUsage(queryUsage + 1)
|
// await assertQueryUsage(queryUsage + 1)
|
||||||
|
@ -92,7 +106,7 @@ describe("/rows", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${table._id}/rows/${existing._id}`)
|
.get(`/api/${table._id}/rows/${existing._id}`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body).toEqual({
|
expect(res.body).toEqual({
|
||||||
|
@ -110,7 +124,7 @@ describe("/rows", () => {
|
||||||
const newRow = {
|
const newRow = {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
name: "Second Contact",
|
name: "Second Contact",
|
||||||
status: "new"
|
status: "new",
|
||||||
}
|
}
|
||||||
await config.createRow()
|
await config.createRow()
|
||||||
await config.createRow(newRow)
|
await config.createRow(newRow)
|
||||||
|
@ -119,7 +133,7 @@ describe("/rows", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${table._id}/rows`)
|
.get(`/api/${table._id}/rows`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.length).toBe(2)
|
expect(res.body.length).toBe(2)
|
||||||
|
@ -135,17 +149,36 @@ describe("/rows", () => {
|
||||||
await request
|
await request
|
||||||
.get(`/api/${table._id}/rows/not-a-valid-id`)
|
.get(`/api/${table._id}/rows/not-a-valid-id`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(404)
|
.expect(404)
|
||||||
await assertQueryUsage(queryUsage) // no change
|
await assertQueryUsage(queryUsage) // no change
|
||||||
})
|
})
|
||||||
|
|
||||||
it("row values are coerced", async () => {
|
it("row values are coerced", async () => {
|
||||||
const str = {type:"string", constraints: { type: "string", presence: false }}
|
const str = {
|
||||||
const attachment = {type:"attachment", constraints: { type: "array", presence: false }}
|
type: "string",
|
||||||
const bool = {type:"boolean", constraints: { type: "boolean", presence: false }}
|
constraints: { type: "string", presence: false },
|
||||||
const number = {type:"number", constraints: { type: "number", presence: false }}
|
}
|
||||||
const datetime = {type:"datetime", constraints: { type: "string", presence: false, datetime: {earliest:"", latest: ""} }}
|
const attachment = {
|
||||||
|
type: "attachment",
|
||||||
|
constraints: { type: "array", presence: false },
|
||||||
|
}
|
||||||
|
const bool = {
|
||||||
|
type: "boolean",
|
||||||
|
constraints: { type: "boolean", presence: false },
|
||||||
|
}
|
||||||
|
const number = {
|
||||||
|
type: "number",
|
||||||
|
constraints: { type: "number", presence: false },
|
||||||
|
}
|
||||||
|
const datetime = {
|
||||||
|
type: "datetime",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
presence: false,
|
||||||
|
datetime: { earliest: "", latest: "" },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
table = await config.createTable({
|
table = await config.createTable({
|
||||||
name: "TestTable2",
|
name: "TestTable2",
|
||||||
|
@ -171,9 +204,9 @@ describe("/rows", () => {
|
||||||
boolUndefined: bool,
|
boolUndefined: bool,
|
||||||
boolString: bool,
|
boolString: bool,
|
||||||
boolBool: bool,
|
boolBool: bool,
|
||||||
attachmentNull : attachment,
|
attachmentNull: attachment,
|
||||||
attachmentUndefined : attachment,
|
attachmentUndefined: attachment,
|
||||||
attachmentEmpty : attachment,
|
attachmentEmpty: attachment,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -198,9 +231,9 @@ describe("/rows", () => {
|
||||||
boolString: "true",
|
boolString: "true",
|
||||||
boolBool: true,
|
boolBool: true,
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
attachmentNull : null,
|
attachmentNull: null,
|
||||||
attachmentUndefined : undefined,
|
attachmentUndefined: undefined,
|
||||||
attachmentEmpty : "",
|
attachmentEmpty: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = (await config.createRow(row))._id
|
const id = (await config.createRow(row))._id
|
||||||
|
@ -218,7 +251,9 @@ describe("/rows", () => {
|
||||||
expect(saved.datetimeEmptyString).toBe(null)
|
expect(saved.datetimeEmptyString).toBe(null)
|
||||||
expect(saved.datetimeNull).toBe(null)
|
expect(saved.datetimeNull).toBe(null)
|
||||||
expect(saved.datetimeUndefined).toBe(undefined)
|
expect(saved.datetimeUndefined).toBe(undefined)
|
||||||
expect(saved.datetimeString).toBe(new Date(row.datetimeString).toISOString())
|
expect(saved.datetimeString).toBe(
|
||||||
|
new Date(row.datetimeString).toISOString()
|
||||||
|
)
|
||||||
expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString())
|
expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString())
|
||||||
expect(saved.boolNull).toBe(null)
|
expect(saved.boolNull).toBe(null)
|
||||||
expect(saved.boolEmpty).toBe(null)
|
expect(saved.boolEmpty).toBe(null)
|
||||||
|
@ -247,10 +282,12 @@ describe("/rows", () => {
|
||||||
name: "Updated Name",
|
name: "Updated Name",
|
||||||
})
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`)
|
expect(res.res.statusMessage).toEqual(
|
||||||
|
`${table.name} updated successfully.`
|
||||||
|
)
|
||||||
expect(res.body.name).toEqual("Updated Name")
|
expect(res.body.name).toEqual("Updated Name")
|
||||||
expect(res.body.description).toEqual(existing.description)
|
expect(res.body.description).toEqual(existing.description)
|
||||||
|
|
||||||
|
@ -292,16 +329,14 @@ describe("/rows", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.delete(`/api/${table._id}/rows`)
|
.delete(`/api/${table._id}/rows`)
|
||||||
.send({
|
.send({
|
||||||
rows: [
|
rows: [createdRow],
|
||||||
createdRow
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body[0]._id).toEqual(createdRow._id)
|
expect(res.body[0]._id).toEqual(createdRow._id)
|
||||||
await assertRowUsage(rowUsage -1)
|
await assertRowUsage(rowUsage - 1)
|
||||||
await assertQueryUsage(queryUsage +1)
|
await assertQueryUsage(queryUsage + 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -314,9 +349,9 @@ describe("/rows", () => {
|
||||||
.post(`/api/${table._id}/rows/validate`)
|
.post(`/api/${table._id}/rows/validate`)
|
||||||
.send({ name: "ivan" })
|
.send({ name: "ivan" })
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.valid).toBe(true)
|
expect(res.body.valid).toBe(true)
|
||||||
expect(Object.keys(res.body.errors)).toEqual([])
|
expect(Object.keys(res.body.errors)).toEqual([])
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
|
@ -331,9 +366,9 @@ describe("/rows", () => {
|
||||||
.post(`/api/${table._id}/rows/validate`)
|
.post(`/api/${table._id}/rows/validate`)
|
||||||
.send({ name: 1 })
|
.send({ name: 1 })
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.valid).toBe(false)
|
expect(res.body.valid).toBe(false)
|
||||||
expect(Object.keys(res.body.errors)).toEqual(["name"])
|
expect(Object.keys(res.body.errors)).toEqual(["name"])
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
|
@ -351,19 +386,16 @@ describe("/rows", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.delete(`/api/${table._id}/rows`)
|
.delete(`/api/${table._id}/rows`)
|
||||||
.send({
|
.send({
|
||||||
rows: [
|
rows: [row1, row2],
|
||||||
row1,
|
|
||||||
row2,
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.length).toEqual(2)
|
expect(res.body.length).toEqual(2)
|
||||||
await loadRow(row1._id, 404)
|
await loadRow(row1._id, 404)
|
||||||
await assertRowUsage(rowUsage - 2)
|
await assertRowUsage(rowUsage - 2)
|
||||||
await assertQueryUsage(queryUsage +1)
|
await assertQueryUsage(queryUsage + 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -376,12 +408,12 @@ describe("/rows", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/views/${table._id}`)
|
.get(`/api/views/${table._id}`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.length).toEqual(1)
|
expect(res.body.length).toEqual(1)
|
||||||
expect(res.body[0]._id).toEqual(row._id)
|
expect(res.body[0]._id).toEqual(row._id)
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
await assertQueryUsage(queryUsage +1)
|
await assertQueryUsage(queryUsage + 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should throw an error if view doesn't exist", async () => {
|
it("should throw an error if view doesn't exist", async () => {
|
||||||
|
@ -406,7 +438,7 @@ describe("/rows", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/views/${view.name}`)
|
.get(`/api/views/${view.name}`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.length).toEqual(1)
|
expect(res.body.length).toEqual(1)
|
||||||
expect(res.body[0]._id).toEqual(row._id)
|
expect(res.body[0]._id).toEqual(row._id)
|
||||||
|
@ -418,21 +450,24 @@ describe("/rows", () => {
|
||||||
|
|
||||||
describe("fetchEnrichedRows", () => {
|
describe("fetchEnrichedRows", () => {
|
||||||
it("should allow enriching some linked rows", async () => {
|
it("should allow enriching some linked rows", async () => {
|
||||||
const { table, firstRow, secondRow } = await doInTenant(setup.structures.TENANT_ID, async () => {
|
const { table, firstRow, secondRow } = await doInTenant(
|
||||||
const table = await config.createLinkedTable()
|
setup.structures.TENANT_ID,
|
||||||
const firstRow = await config.createRow({
|
async () => {
|
||||||
name: "Test Contact",
|
const table = await config.createLinkedTable()
|
||||||
description: "original description",
|
const firstRow = await config.createRow({
|
||||||
tableId: table._id
|
name: "Test Contact",
|
||||||
})
|
description: "original description",
|
||||||
const secondRow = await config.createRow({
|
tableId: table._id,
|
||||||
name: "Test 2",
|
})
|
||||||
description: "og desc",
|
const secondRow = await config.createRow({
|
||||||
link: [{_id: firstRow._id}],
|
name: "Test 2",
|
||||||
tableId: table._id,
|
description: "og desc",
|
||||||
})
|
link: [{ _id: firstRow._id }],
|
||||||
return { table, firstRow, secondRow }
|
tableId: table._id,
|
||||||
})
|
})
|
||||||
|
return { table, firstRow, secondRow }
|
||||||
|
}
|
||||||
|
)
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
const queryUsage = await getQueryUsage()
|
const queryUsage = await getQueryUsage()
|
||||||
|
|
||||||
|
@ -440,7 +475,7 @@ describe("/rows", () => {
|
||||||
const resBasic = await request
|
const resBasic = await request
|
||||||
.get(`/api/${table._id}/rows/${secondRow._id}`)
|
.get(`/api/${table._id}/rows/${secondRow._id}`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(resBasic.body.link[0]._id).toBe(firstRow._id)
|
expect(resBasic.body.link[0]._id).toBe(firstRow._id)
|
||||||
expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact")
|
expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact")
|
||||||
|
@ -449,14 +484,14 @@ describe("/rows", () => {
|
||||||
const resEnriched = await request
|
const resEnriched = await request
|
||||||
.get(`/api/${table._id}/${secondRow._id}/enrich`)
|
.get(`/api/${table._id}/${secondRow._id}/enrich`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(resEnriched.body.link.length).toBe(1)
|
expect(resEnriched.body.link.length).toBe(1)
|
||||||
expect(resEnriched.body.link[0]._id).toBe(firstRow._id)
|
expect(resEnriched.body.link[0]._id).toBe(firstRow._id)
|
||||||
expect(resEnriched.body.link[0].name).toBe("Test Contact")
|
expect(resEnriched.body.link[0].name).toBe("Test Contact")
|
||||||
expect(resEnriched.body.link[0].description).toBe("original description")
|
expect(resEnriched.body.link[0].description).toBe("original description")
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
await assertQueryUsage(queryUsage +2)
|
await assertQueryUsage(queryUsage + 2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -466,9 +501,11 @@ describe("/rows", () => {
|
||||||
const row = await config.createRow({
|
const row = await config.createRow({
|
||||||
name: "test",
|
name: "test",
|
||||||
description: "test",
|
description: "test",
|
||||||
attachment: [{
|
attachment: [
|
||||||
key: `${config.getAppId()}/attachments/test/thing.csv`,
|
{
|
||||||
}],
|
key: `${config.getAppId()}/attachments/test/thing.csv`,
|
||||||
|
},
|
||||||
|
],
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
})
|
})
|
||||||
// the environment needs configured for this
|
// the environment needs configured for this
|
||||||
|
@ -482,4 +519,49 @@ describe("/rows", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("exportData", () => {
|
||||||
|
it("should allow exporting all columns", async () => {
|
||||||
|
const existing = await config.createRow()
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/${table._id}/rows/exportRows?format=json`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send({
|
||||||
|
rows: [existing._id],
|
||||||
|
})
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
const results = JSON.parse(res.text)
|
||||||
|
expect(results.length).toEqual(1)
|
||||||
|
const row = results[0]
|
||||||
|
|
||||||
|
// Ensure all original columns were exported
|
||||||
|
expect(Object.keys(row).length).toBeGreaterThanOrEqual(
|
||||||
|
Object.keys(existing).length
|
||||||
|
)
|
||||||
|
Object.keys(existing).forEach(key => {
|
||||||
|
expect(row[key]).toEqual(existing[key])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow exporting only certain columns", async () => {
|
||||||
|
const existing = await config.createRow()
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/${table._id}/rows/exportRows?format=json`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send({
|
||||||
|
rows: [existing._id],
|
||||||
|
columns: ["_id"],
|
||||||
|
})
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
const results = JSON.parse(res.text)
|
||||||
|
expect(results.length).toEqual(1)
|
||||||
|
const row = results[0]
|
||||||
|
|
||||||
|
// Ensure only the _id column was exported
|
||||||
|
expect(Object.keys(row).length).toEqual(1)
|
||||||
|
expect(row._id).toEqual(existing._id)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue